smartpipe-cli 1.4.0rc1__tar.gz → 1.4.0rc2__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 (241) hide show
  1. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/CHANGELOG.md +235 -0
  2. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/CITATION.cff +1 -1
  3. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/CONTRIBUTING.md +18 -0
  4. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/PKG-INFO +54 -7
  5. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/README.md +51 -5
  6. smartpipe_cli-1.4.0rc2/docs/assets/demo-thumb.jpg +0 -0
  7. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/concepts/feeding-smartpipe.md +36 -3
  8. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/concepts/models-and-providers.md +47 -0
  9. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/concepts/output-formats.md +25 -0
  10. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/concepts/pipes-and-items.md +5 -4
  11. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/concepts/structured-output.md +40 -8
  12. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/concepts/the-item.md +22 -0
  13. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/cookbook/README.md +15 -0
  14. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/cookbook/contract-extraction.md +3 -3
  15. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/cookbook/customer-feedback.md +6 -3
  16. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/cookbook/live-monitoring.md +1 -1
  17. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/cookbook/log-triage.md +1 -1
  18. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/cookbook/meeting-digest.md +2 -1
  19. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/cookbook/ranking-documents.md +1 -1
  20. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/cookbook/training-data-prep.md +1 -1
  21. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/cookbook/visualizing-results.md +3 -3
  22. smartpipe_cli-1.4.0rc2/docs/demo/index.html +26 -0
  23. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/index.md +24 -2
  24. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/inputs/files.md +6 -0
  25. smartpipe_cli-1.4.0rc2/docs/install.md +94 -0
  26. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/learn/1-first-pipeline.md +8 -5
  27. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/learn/2-structured-data.md +39 -6
  28. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/learn/3-files-and-media.md +3 -2
  29. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/reference/cli.md +37 -6
  30. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/reference/sem-files.md +43 -28
  31. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/troubleshooting.md +11 -12
  32. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/verbs/embed.md +23 -4
  33. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/verbs/extend.md +5 -3
  34. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/verbs/map.md +8 -5
  35. smartpipe_cli-1.4.0rc2/docs/verbs/readable.md +53 -0
  36. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/verbs/sort.md +6 -3
  37. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/verbs/split.md +7 -6
  38. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/verbs/summarize.md +2 -1
  39. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/verbs/top-k.md +12 -4
  40. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/verbs/where.md +6 -3
  41. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/mkdocs.yml +15 -0
  42. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/pyproject.toml +8 -2
  43. smartpipe_cli-1.4.0rc2/qa/fixtures/README.md +7 -0
  44. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/chart_cmd.py +15 -5
  45. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/cluster_cmd.py +1 -1
  46. smartpipe_cli-1.4.0rc2/src/smartpipe/cli/config_cmd.py +564 -0
  47. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/doctor_cmd.py +10 -8
  48. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/embed_cmd.py +17 -1
  49. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/extend_cmd.py +4 -0
  50. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/filter_cmd.py +10 -1
  51. smartpipe_cli-1.4.0rc2/src/smartpipe/cli/graph_cmd.py +185 -0
  52. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/input_options.py +15 -2
  53. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/map_cmd.py +4 -0
  54. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/probe_cmd.py +18 -0
  55. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/read_cmd.py +4 -2
  56. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/readable_cmd.py +20 -3
  57. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/reduce_cmd.py +4 -0
  58. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/root.py +18 -1
  59. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/run_cmd.py +3 -0
  60. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/schema_cmd.py +8 -8
  61. smartpipe_cli-1.4.0rc2/src/smartpipe/cli/schema_workshop.py +318 -0
  62. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/screens.py +50 -1
  63. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/sem_file.py +14 -0
  64. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/top_k_cmd.py +17 -1
  65. smartpipe_cli-1.4.0rc2/src/smartpipe/cli/update_cmd.py +103 -0
  66. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/write_cmd.py +1 -1
  67. smartpipe_cli-1.4.0rc2/src/smartpipe/config/picker.py +353 -0
  68. smartpipe_cli-1.4.0rc2/src/smartpipe/config/state_cache.py +128 -0
  69. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/config/store.py +12 -0
  70. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/container.py +106 -4
  71. smartpipe_cli-1.4.0rc2/src/smartpipe/core/install_channel.py +60 -0
  72. smartpipe_cli-1.4.0rc2/src/smartpipe/core/versions.py +87 -0
  73. smartpipe_cli-1.4.0rc2/src/smartpipe/engine/chart.py +234 -0
  74. smartpipe_cli-1.4.0rc2/src/smartpipe/engine/graphkg.py +484 -0
  75. smartpipe_cli-1.4.0rc2/src/smartpipe/engine/graphout.py +513 -0
  76. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/engine/predicate.py +19 -3
  77. smartpipe_cli-1.4.0rc2/src/smartpipe/engine/preview.py +120 -0
  78. smartpipe_cli-1.4.0rc2/src/smartpipe/engine/progressbar.py +68 -0
  79. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/engine/prompts.py +203 -21
  80. smartpipe_cli-1.4.0rc2/src/smartpipe/engine/repair.py +137 -0
  81. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/engine/schema.py +171 -11
  82. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/engine/schema_dsl.py +20 -4
  83. smartpipe_cli-1.4.0rc2/src/smartpipe/engine/schema_repl.py +421 -0
  84. smartpipe_cli-1.4.0rc2/src/smartpipe/engine/temporal.py +166 -0
  85. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/engine/timebin.py +2 -1
  86. smartpipe_cli-1.4.0rc2/src/smartpipe/io/arrow_menu.py +198 -0
  87. smartpipe_cli-1.4.0rc2/src/smartpipe/io/csvrows.py +174 -0
  88. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/io/inputs.py +1 -1
  89. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/io/items.py +54 -3
  90. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/io/metering.py +3 -1
  91. smartpipe_cli-1.4.0rc2/src/smartpipe/io/preview.py +296 -0
  92. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/io/progress.py +45 -33
  93. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/io/readers.py +320 -29
  94. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/io/render.py +20 -15
  95. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/io/tty.py +1 -0
  96. smartpipe_cli-1.4.0rc2/src/smartpipe/io/update_check.py +214 -0
  97. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/io/writers.py +18 -1
  98. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/models/anthropic_adapter.py +9 -0
  99. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/models/budget.py +34 -1
  100. smartpipe_cli-1.4.0rc2/src/smartpipe/models/catalogs.py +134 -0
  101. smartpipe_cli-1.4.0rc2/src/smartpipe/models/local_ner.py +299 -0
  102. smartpipe_cli-1.4.0rc2/src/smartpipe/models/ocr.py +218 -0
  103. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/models/openai_codex.py +9 -1
  104. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/parsing/detect.py +15 -1
  105. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/chart.py +58 -15
  106. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/common.py +85 -12
  107. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/convert.py +14 -2
  108. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/embed.py +61 -10
  109. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/extend.py +11 -3
  110. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/filter.py +28 -8
  111. smartpipe_cli-1.4.0rc2/src/smartpipe/verbs/graph.py +492 -0
  112. smartpipe_cli-1.4.0rc2/src/smartpipe/verbs/graphfull.py +614 -0
  113. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/map.py +26 -10
  114. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/oversize.py +14 -6
  115. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/readable.py +11 -1
  116. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/reduce.py +52 -23
  117. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/sortverb.py +22 -3
  118. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/top_k.py +112 -15
  119. smartpipe_cli-1.4.0rc1/docs/assets/demo-thumb.jpg +0 -0
  120. smartpipe_cli-1.4.0rc1/docs/demo/index.html +0 -24
  121. smartpipe_cli-1.4.0rc1/docs/install.md +0 -68
  122. smartpipe_cli-1.4.0rc1/src/smartpipe/cli/config_cmd.py +0 -338
  123. smartpipe_cli-1.4.0rc1/src/smartpipe/engine/chart.py +0 -143
  124. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/.gitignore +0 -0
  125. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/LICENSE +0 -0
  126. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/NOTICE +0 -0
  127. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/demo/video/README.md +0 -0
  128. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/demo/video/src/Main.tsx +0 -0
  129. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/demo/video/src/Root.tsx +0 -0
  130. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/demo/video/src/components/Background.tsx +0 -0
  131. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/demo/video/src/components/Caption.tsx +0 -0
  132. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/demo/video/src/components/FileGlyph.tsx +0 -0
  133. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/demo/video/src/components/SceneFrame.tsx +0 -0
  134. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/demo/video/src/components/Terminal.tsx +0 -0
  135. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/demo/video/src/components/Wordmark.tsx +0 -0
  136. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/demo/video/src/config.ts +0 -0
  137. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/demo/video/src/font.ts +0 -0
  138. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/demo/video/src/index.ts +0 -0
  139. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/demo/video/src/scenes/Close.tsx +0 -0
  140. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/demo/video/src/scenes/ColdOpen.tsx +0 -0
  141. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/demo/video/src/scenes/CostHonesty.tsx +0 -0
  142. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/demo/video/src/scenes/Hook.tsx +0 -0
  143. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/demo/video/src/scenes/Multimodal.tsx +0 -0
  144. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/demo/video/src/scenes/Scale.tsx +0 -0
  145. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/comparison.md +0 -0
  146. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/cookbook/invoice-reconciliation.md +0 -0
  147. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/cookbook/stream-enrichment.md +0 -0
  148. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/cookbook/video-qa.md +0 -0
  149. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/learn/4-free-verbs.md +0 -0
  150. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/learn/5-scale-and-cost.md +0 -0
  151. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/learn/6-pipelines-that-last.md +0 -0
  152. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/privacy.md +0 -0
  153. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/quickstart.md +0 -0
  154. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/reference/agents.md +0 -0
  155. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/reference/custom-verbs.md +0 -0
  156. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/verbs/cluster.md +0 -0
  157. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/verbs/diff.md +0 -0
  158. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/verbs/distinct.md +0 -0
  159. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/verbs/filter.md +0 -0
  160. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/verbs/getschema.md +0 -0
  161. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/verbs/join.md +0 -0
  162. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/verbs/outliers.md +0 -0
  163. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/verbs/reduce.md +0 -0
  164. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/docs/verbs/sample.md +0 -0
  165. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/qa/README.md +0 -0
  166. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/__init__.py +0 -0
  167. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/__main__.py +0 -0
  168. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/assets/probe.png +0 -0
  169. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/assets/probe.txt +0 -0
  170. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/assets/probe.wav +0 -0
  171. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/__init__.py +0 -0
  172. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/auth_cmd.py +0 -0
  173. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/cache_cmd.py +0 -0
  174. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/cite_cmd.py +0 -0
  175. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/completions.py +0 -0
  176. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/diff_cmd.py +0 -0
  177. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/distinct_cmd.py +0 -0
  178. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/echo_cmd.py +0 -0
  179. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/getschema_cmd.py +0 -0
  180. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/interrupts.py +0 -0
  181. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/join_cmd.py +0 -0
  182. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/outliers_cmd.py +0 -0
  183. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/sample_cmd.py +0 -0
  184. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/sort_cmd.py +0 -0
  185. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/split_cmd.py +0 -0
  186. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/summarize_cmd.py +0 -0
  187. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/usage_cmd.py +0 -0
  188. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/cli/where_cmd.py +0 -0
  189. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/config/__init__.py +0 -0
  190. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/config/credentials.py +0 -0
  191. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/config/display.py +0 -0
  192. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/config/doctor.py +0 -0
  193. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/config/paths.py +0 -0
  194. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/core/__init__.py +0 -0
  195. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/core/errors.py +0 -0
  196. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/core/jsontools.py +0 -0
  197. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/engine/__init__.py +0 -0
  198. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/engine/aggregate.py +0 -0
  199. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/engine/blocking.py +0 -0
  200. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/engine/chunking.py +0 -0
  201. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/engine/clustering.py +0 -0
  202. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/engine/ranking.py +0 -0
  203. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/engine/runner.py +0 -0
  204. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/engine/tally.py +0 -0
  205. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/engine/units.py +0 -0
  206. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/engine/windows.py +0 -0
  207. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/io/__init__.py +0 -0
  208. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/io/diagnostics.py +0 -0
  209. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/io/leaderboard.py +0 -0
  210. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/io/text.py +0 -0
  211. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/io/usage.py +0 -0
  212. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/models/__init__.py +0 -0
  213. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/models/base.py +0 -0
  214. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/models/cache.py +0 -0
  215. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/models/gemini_native.py +0 -0
  216. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/models/http_support.py +0 -0
  217. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/models/jina.py +0 -0
  218. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/models/local_embed.py +0 -0
  219. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/models/ollama.py +0 -0
  220. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/models/openai_compat.py +0 -0
  221. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/models/openai_oauth.py +0 -0
  222. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/models/resolve.py +0 -0
  223. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/models/retry.py +0 -0
  224. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/models/stt.py +0 -0
  225. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/models/windows.py +0 -0
  226. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/parsing/__init__.py +0 -0
  227. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/parsing/extract.py +0 -0
  228. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/py.typed +0 -0
  229. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/__init__.py +0 -0
  230. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/cluster.py +0 -0
  231. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/diff.py +0 -0
  232. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/distinct.py +0 -0
  233. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/getschema.py +0 -0
  234. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/join.py +0 -0
  235. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/outliers.py +0 -0
  236. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/sample.py +0 -0
  237. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/split.py +0 -0
  238. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/summarize.py +0 -0
  239. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/where.py +0 -0
  240. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/src/smartpipe/verbs/write.py +0 -0
  241. {smartpipe_cli-1.4.0rc1 → smartpipe_cli-1.4.0rc2}/tests/corpus/README.md +0 -0
@@ -9,7 +9,68 @@ Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) · Versioning:
9
9
 
10
10
  The identity release.
11
11
 
12
+ ### Knowledge graphs (the highlight)
13
+ - **`smartpipe graph --fast` turns a corpus into a knowledge graph for
14
+ exactly $0.** A local zero-shot NER model (GLiNER-small over ONNX -
15
+ no new dependencies, no torch, a one-time ~190 MB download like the
16
+ local embedder) finds YOUR entity types (`--entities "person, vessel,
17
+ account"`), entities co-occurring in a window become weighted edges,
18
+ near-duplicate names fold into one node (disclosed), and every edge
19
+ carries its `sources` - the files, pages, and minutes where it was
20
+ seen. Zero model calls, pinned by test. Free transcripts (local
21
+ whisper) mean audio and video speech join the graph; scans and
22
+ images wait for the paid mode, counted out loud.
23
+ - **Six ways out, all deterministic**: `.graphml` (Gephi), `.dot`
24
+ (Graphviz), `.mmd` (Mermaid), `nodes.csv`+`edges.csv` (Neo4j/Kuzu),
25
+ a self-contained interactive `.html` (search, weight slider, hover
26
+ cards with clickable `file://` evidence links), or a trailing `/`
27
+ for an Obsidian vault of wikilinked entity notes.
28
+ - **A focus prompt buys named relations.** `smartpipe graph "people,
29
+ orgs, and money flows" case/**/*` extracts typed triples per chunk
30
+ through the full multimodal ladders - vision, OCR, native video -
31
+ with `--entities`/`--relations` compiling to enums when you want a
32
+ strict ontology. The cost plan prints BEFORE any spend (`~810
33
+ extraction calls; belt is 500 - the graph will be partial`), a
34
+ terminal decline exits clean at zero calls, and a belted run drains
35
+ to a valid partial graph at exit 1, never a fake success.
36
+ - **The hybrid ladder: `--name-top 200`.** The free pass finds the
37
+ candidates; the model names only the strongest links - one call per
38
+ edge, and if the belt runs out the remainder keeps its honest
39
+ `co-occurs` label, disclosed. Free graph in seconds; name the top
40
+ edges for cents.
41
+ - **Bring your own edges.** Records with `{source, target}` or
42
+ `{subject, relation, object}` on stdin skip extraction entirely -
43
+ canonicalize, fold, serialize. Your own `extend` pipeline is the
44
+ power path.
45
+
12
46
  ### The item — one law for everything in a pipe
47
+ - **Dates are a type, and they come back ISO.** `{due date}` and
48
+ `{ts datetime}` join the brace grammar. However the model phrases it
49
+ ("Jan 15, 2026", "15/01/2026"), the field canonicalizes to
50
+ `YYYY-MM-DD` / full ISO-8601 - offsets preserved, never invented;
51
+ genuinely ambiguous slash-dates read month-first and say so on
52
+ stderr. Downstream just works: `where 'due >= "2026-01-01"'`
53
+ compares temporally, `sort --by due` orders by instant, and
54
+ `summarize 'count() by bin(due, 1d)'` buckets date-only values.
55
+ - **The model sees your data framed, not dumped.** Every item payload
56
+ now arrives inside an `<input>` fence - records rendered as clean
57
+ YAML-ish (the `__` plumbing excluded), text as itself. The
58
+ instruction can no longer blur into the data, and the fence is the
59
+ foundation the planned request-batching builds on.
60
+ - **CSV is a first-class row format.** `--as csv` (and `.csv`/`.tsv`
61
+ extension defaults - tab dialect for `.tsv`) reads the header row as
62
+ field names and streams every data row as a record, with per-cell
63
+ int → float → string coercion and multi-line quoted cells handled. A
64
+ ragged row is a loud error naming the file and physical line; rows
65
+ carry `__source {"as": "csv", "line": N}`. Works on stdin too, and
66
+ `.sem` files gain the `as` key.
67
+ - **Malformed model replies repair for free before they cost money.**
68
+ A structured reply that fails to parse now passes through a
69
+ deterministic fixer first - code fences, JSON-island extraction,
70
+ Python-repr literals, trailing commas, quote fixes, all validated by
71
+ an actual parse - and only escalates to the paid model-repair round
72
+ trip when that fails. Disclosed once per run:
73
+ `note: N replies repaired deterministically (fences/commas/quotes)`.
13
74
  - **The `__` metadata spine.** Tool metadata lives in a reserved
14
75
  double-underscore namespace that rides every record: `__source` (path plus
15
76
  HOW the item was cut - file, lines, jsonl, pages, minutes, segment index),
@@ -70,12 +131,182 @@ The identity release.
70
131
  model calls. Verb tables mark the free rungs.
71
132
 
72
133
  ### The terminal behaves
134
+ - **A real progress bar.** When the total is knowable (file lists), the
135
+ status line becomes `[██████░░░░░░░░░] 41% · 205/500 · 12/s · ~25s
136
+ left` - fill and percent truncate so 100% is earned, the ETA appears
137
+ once the first item completes, ASCII terminals get `[=====>....]`,
138
+ and multi-stage runs prefix the stage name. Streams keep the
139
+ count-and-rate line: a `tail -f` has no percent.
140
+ - **Braces extract lists of objects.** `{events {name string, when
141
+ date, severity enum(low, high)}[]}` pulls every event out of an item
142
+ in one call, typed and validated - inner dates still canonicalize to
143
+ ISO, `--explode events` turns the list into one row each. One level
144
+ deep by design; deeper nesting faults free at parse time with the
145
+ two-pass hint.
73
146
  - Result writes pause/erase/redraw the status line under an arbiter - the
74
147
  spinner can never interleave with output again. Only the final pipe stage
75
148
  (stdout a TTY) animates; mid-pipe stages stay line-atomic.
76
149
  - Records render at the TTY as YAML-ish blocks. The welcome screen links
77
150
  docs, cookbook, and issues. The wizard offers to install shell
78
151
  completions (consented, idempotent).
152
+ - **`chart` re-platformed: plotext draws the terminal, matplotlib renders
153
+ `--save`.** TTY bars get color (cyan bars, green time-series); piped or
154
+ `NO_COLOR` output keeps the plain-ASCII contract byte-for-byte. `--save`
155
+ now writes SVG or PNG by extension (identity-styled, deterministic
156
+ output); svgwrite - unmaintained since 2022 - leaves the tree. Both
157
+ libraries ship in core per the no-extras rule; imports stay
158
+ function-local so startup holds. The run receipt now reads
159
+ `run: ↑40 ↓25 tok` (arrows for in/out). The wizard validates model names
160
+ before saving (two strikes, then a typed fault), prints completions
161
+ before the paste-bait "Try it" line, prefers a sensible local default
162
+ over alphabetical luck (cloud tags compete equally), and speaks in the
163
+ same color voice as the other commands with a menu of detected local
164
+ tags and provider-prefixed cloud examples.
165
+ - **Docs bug, live-caught: `cluster | chart` drew flat bars.** The summary
166
+ rows are one-per-cluster, so charting them counts every theme once. The
167
+ README quick-tour step, the `cluster` help epilog, and the `.sem`
168
+ pipeline example now route `cluster --explode members` into
169
+ `chart cluster --top 8`, which draws real sizes.
170
+
171
+ ### Every example, run for real
172
+ - **`map` and `extend` records finally carry their provenance.** The
173
+ `__source` spine - the law said it rides every record - was being
174
+ dropped by braces extraction: a reader-stamped row went in with
175
+ `{"path", "as", "line"}` and came out with only the extracted fields.
176
+ Every record leaving `map`/`extend` now carries `__source` (incoming
177
+ spines adopted verbatim, fresh ones stamped from the item's
178
+ provenance), which also means the terminal preview now shows the dim
179
+ file-and-line origin under each block. `--bare` still strips it.
180
+ - **Docs truth sweep** (owner-reported): four `echo "... $1250"`
181
+ examples silently shell-expanded to "250" - single-quoted; text files
182
+ are declared one-item-per-line at first use; "everything outside the
183
+ braces is the instruction" stated wherever braces are taught; typed
184
+ braces are the norm across the examples; the playground corpus is
185
+ linked from README, docs home, and the cookbook; the demo video plays
186
+ on the docs front page.
187
+ - **Row cuts keep their rows through `filter` and `top_k`.** The grep-l
188
+ contract (match whole files, get paths back) leaked onto `--as jsonl` /
189
+ `--as lines` rows read from a positional file: every matching ROW came
190
+ out as the filename. Both verbs now key path-back on the whole-file cut;
191
+ rows pass through as records. Found by a zero-context agent driving
192
+ smartpipe purely from SKILL.md; pinned in tests both ways.
193
+ - **The docs were audited by executing them**: all 236 example blocks
194
+ (README, docs, SKILL files, CLI help) inventoried, statically checked,
195
+ and ~105 run verbatim against a generated corpus of real-format files.
196
+ Three code bugs surfaced and are fixed with pinning tests:
197
+ - **Quoted globs reach the reader.** `smartpipe 'logs/*.jsonl'` - a
198
+ documented form - exited 64 ("no verb"); unexpanded glob tokens now
199
+ route to reader mode, and an unmatched glob errs loudly.
200
+ - **Video is refused pre-send on wires that can't watch.** The
201
+ ChatGPT-login (codex) and anthropic adapters silently dropped video
202
+ parts and sent prompt-only requests - the model answered "no video
203
+ provided", no degraded note fired, and video-RAG examples embedded
204
+ that refusal prose as vectors. Both wires now raise before sending,
205
+ so the documented ladder (`degraded: … video → frames+audio`)
206
+ actually engages.
207
+ - 7 broken and 12 misleading example sites corrected against observed
208
+ behavior (SKILL files now run verbatim; the `.sem` key table is
209
+ re-derived from the runtime's own validation errors; `__score`
210
+ spelling; stale "oversized items are refused" claims rewritten for
211
+ auto-chunking).
212
+
213
+ ### The terminal shows your media
214
+ - **Every block at the terminal gets a number.** The human view opens
215
+ each record block with a cyan `#N` - so "look at object 5" is a thing
216
+ you can say. The ordinal is the one handle every output is guaranteed
217
+ to have (provenance can repeat across rows - fifty pages of one PDF
218
+ share a path - or be absent on plain text). Display only: piped
219
+ output is byte-identical.
220
+ - **Media previews at the human view.** At a terminal (and through
221
+ `readable`), the first media part of an item now renders under its
222
+ summary line: images as color thumbnails, video as a three-frame strip
223
+ sampled at 10/50/90% of its duration (never frame zero - intros are
224
+ black), audio as a peak-envelope waveform. Audio and video that still
225
+ live on disk get a clickable `▶ play (0:42, 2.1 MB)` link (OSC 8 -
226
+ opens your system player in iTerm2/kitty/WezTerm/Ghostty/Windows
227
+ Terminal). Piped output, JSONL, NO_COLOR, and `--bare` are
228
+ byte-identical to before - previews exist only where a human is
229
+ looking. `smartpipe config media-previews off` turns them off.
230
+
231
+ ### Documents parse where they enter, vectors stay honest
232
+ - **The `ocr-model` role: a document parser at ingestion.** Set
233
+ `smartpipe config ocr-model mistral/mistral-ocr-latest` (or
234
+ `SMARTPIPE_OCR_MODEL`, or `--ocr-model` per run) and ingested PDFs and
235
+ images parse through it - one item per page on the `pages` cut,
236
+ markdown as the text, disclosed per row and metered as a paid
237
+ conversion. Mistral refs ride the dedicated `/v1/ocr` wire
238
+ (live-verified, whole PDFs in one call); any other model ref works as
239
+ chat-vision with extract-the-text framing, so `ollama/llava` is a free
240
+ local OCR. Parse failures fall back to the local extraction ladder,
241
+ disclosed, never fatal. Unset = exactly the old behavior.
242
+ - **The `media-embed-model` role: one joint space for pixels and prose.**
243
+ Text keeps `embed-model`; media routes to the joint-space model
244
+ (jina-clip-v2 and friends). If a run would mix two vector spaces, the
245
+ geometry fence stops it with exit 64 BEFORE any spend, naming both
246
+ models and both fixes. A text query now ranks an image corpus in the
247
+ joint space - that is the point.
248
+ - **Embed rows carry their provenance.** Output rows are now
249
+ `{"text", "vector", "__embedder", "__source"}` - the spine like every
250
+ other verb, plus the model that made the vector. `top_k` refuses a
251
+ corpus whose stamp disagrees with the query's embedder (the
252
+ same-dimensions-different-model trap), and reads old-style rows for
253
+ one release. Two bugs died en route: records piped from the reader
254
+ embedded their serialized JSON instead of their content text, and
255
+ `--max-calls` silently demoted pixels to captions by stripping the
256
+ media-embedding capability.
257
+
258
+ ### Setup that reads the room
259
+ - **The schema workshop.** `smartpipe schema` with no arguments at a
260
+ terminal opens a small interactive draft loop - your schema pinned up
261
+ top as colored braces, commands scrolling below: `/add name type`,
262
+ `/drop`, `/test data.jsonl` (per-field coverage bars against your real
263
+ rows), `/example` (a synthetic instance), `/save` (writes schema.json
264
+ and prints the paste-ready braces and `--schema` lines). Zero model
265
+ calls by construction - iterate freely, commit when the bars are
266
+ green. Paste any `{braces}` string to replace the draft. Piped and
267
+ argument invocations are unchanged.
268
+ - **`smartpipe config` is now a provider-first picker.** Detect what's
269
+ already connected (API keys in the environment, a ChatGPT login, local
270
+ Ollama), pick a provider, pick from its LIVE model catalog - arrow keys
271
+ on a real terminal, a numbered prompt everywhere else. Undetected
272
+ providers show the exact `export ..._API_KEY=` line (smartpipe never
273
+ prompts for or stores a key). Catalogs cache for a day; a failed fetch
274
+ degrades to typed input with provider-prefixed examples. Picking a
275
+ provider auto-pairs a coherent embedding model (announced, and never
276
+ overwrites one you chose yourself), and one y/N question adds a backup
277
+ `fallback-model` for provider outages. After a `doctor --probe`,
278
+ catalog entries carry capability chips (`sees, hears - probed 2d ago`)
279
+ - probed facts, never claims. All the setter subcommands still work.
280
+
281
+ ### Getting it and keeping it current
282
+ - **One-line install on every platform.**
283
+ `curl -LsSf https://prabal-rje.github.io/smartpipe/install.sh | sh`
284
+ (macOS/Linux) and the `install.ps1` analog for Windows PowerShell, both
285
+ published at the docs-site root. The script uses Homebrew when present,
286
+ otherwise bootstraps uv and runs `uv tool install smartpipe-cli`;
287
+ `SMARTPIPE_VERSION` pins a version; it ends with a loud
288
+ `smartpipe --version` verify. brew/uv/pipx/pip remain as explicit
289
+ alternatives.
290
+ - **The installers survive the real world.** Rerunning the one-liner
291
+ upgrades in place instead of erroring (brew-, uv-, and
292
+ otherwise-managed installs each get the right move); the uv bootstrap
293
+ falls back to `wget` when `curl` is missing; Alpine/musl systems get
294
+ a wheels warning before anything installs; Rosetta-translated macOS
295
+ shells get an arch hint; GitHub Actions runners get `~/.local/bin`
296
+ appended to `GITHUB_PATH`. Footguns adopted from studying opencode's
297
+ installer. `install.sh` stays readable POSIX sh at 96 lines.
298
+ - **`smartpipe update`.** Detects how smartpipe was installed (homebrew,
299
+ uv tool, pipx, or pip - fingerprinted from the executable path), shows
300
+ the exact upgrade command, asks consent (`--yes` skips), runs it, and
301
+ reports honestly. Unrecognized installs get the per-channel commands
302
+ instead of a guess.
303
+ - **A calm update notice.** At most once a day smartpipe checks PyPI in a
304
+ background thread (2 s cap, silent on any failure) and - on a later
305
+ run, at a terminal, never in CI, never on stdout - prints one dim line:
306
+ `note: smartpipe X.Y.Z is available (you have A.B.C) - run: smartpipe
307
+ update`. Rc users aren't nagged about older stables. Off switches:
308
+ `SMARTPIPE_NO_UPDATE_CHECK=1` or `smartpipe config update-check off`.
309
+ The welcome screen's utility list now includes `update`.
79
310
 
80
311
  ### Docs: a shape, not a pile
81
312
  - New Learn track (`docs/learn/1…6`), `concepts/the-item.md` (the five
@@ -435,6 +666,10 @@ estimated dollars.
435
666
  live-caught). `doctor` now closes with a bold yellow pointer at `--probe`.
436
667
  Also fixed live: streaming `embed` emitted the pre-conversion item text
437
668
  (empty for media), so records now carry the text the vector actually means.
669
+ And the streaming path (piped stdin) skipped the native media route
670
+ entirely - image-only items caption-pivoted even on jina-clip while the
671
+ finite-corpus branch embedded pixels. Both branches now share one router
672
+ (live-verified: `dims: 1024` from jina-clip-v2 on a piped image).
438
673
  - **Gemini watches video natively (D34).** Gemini chat moved to Google's
439
674
  native `:generateContent` wire — the only wired endpoint with video input.
440
675
  `map "what happens?" --in demo.mp4 --model gemini-2.5-flash` sends the
@@ -7,5 +7,5 @@ authors:
7
7
  given-names: Prabal
8
8
  repository-code: "https://github.com/prabal-rje/smartpipe"
9
9
  license: Apache-2.0
10
- version: 1.4.0rc1
10
+ version: 1.4.0rc2
11
11
  date-released: '2026-07-08'
@@ -44,6 +44,24 @@ Optional but recommended: `uv run pre-commit install` wires ruff into your commi
44
44
 
45
45
  Release ritual: [RELEASING.md](RELEASING.md) · upkeep: [MAINTENANCE.md](MAINTENANCE.md).
46
46
 
47
+ ## Docs search (Algolia DocSearch)
48
+
49
+ The site is pre-wired for [DocSearch](https://docsearch.algolia.com/) but ships
50
+ with it OFF: `extra.algolia` in `mkdocs.yml` holds three empty strings, and
51
+ while any of them is empty `overrides/main.html` renders nothing extra -
52
+ mkdocs-material's built-in search keeps working. To activate once the
53
+ DocSearch application is approved:
54
+
55
+ 1. Put the credentials Algolia sends into `mkdocs.yml` → `extra.algolia`
56
+ (`app_id`, `index_name`, and the **search-only** public `api_key` - that
57
+ key is safe to commit; never the admin key).
58
+ 2. `make docs-check` - the strict build must stay green.
59
+ 3. Open the built site and confirm the DocSearch button replaced the
60
+ built-in search box (the override hides `.md-search` and mounts
61
+ docsearch.js v3 in the header).
62
+
63
+ Reverting to built-in search is emptying the three values again.
64
+
47
65
  ## New dependencies
48
66
 
49
67
  Core install weight is a feature: the runtime dependency list is `click`, `httpx`,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: smartpipe-cli
3
- Version: 1.4.0rc1
3
+ Version: 1.4.0rc2
4
4
  Summary: Semantic pipes and queries for your terminal - PDFs, images, audio, video, and text through Unix verbs that understand.
5
5
  Project-URL: Homepage, https://github.com/prabal-rje/smartpipe
6
6
  Project-URL: Changelog, https://github.com/prabal-rje/smartpipe/blob/main/CHANGELOG.md
@@ -28,9 +28,10 @@ Requires-Dist: httpx>=0.27
28
28
  Requires-Dist: imageio-ffmpeg>=0.5
29
29
  Requires-Dist: jsonschema>=4.23
30
30
  Requires-Dist: markitdown[docx,pdf,pptx,xlsx]>=0.1.6; python_version < '3.14'
31
+ Requires-Dist: matplotlib>=3.8
31
32
  Requires-Dist: pdfminer-six>=20231228
33
+ Requires-Dist: plotext>=5
32
34
  Requires-Dist: pypdf>=5.0
33
- Requires-Dist: svgwrite>=1.4
34
35
  Requires-Dist: tomli-w>=1.0
35
36
  Description-Content-Type: text/markdown
36
37
 
@@ -47,17 +48,43 @@ Description-Content-Type: text/markdown
47
48
  Run PDFs, images, audio, video, and text through Unix verbs that understand
48
49
  their input.
49
50
 
50
- [![smartpipe demo - click to play with sound and controls](https://github.com/prabal-rje/smartpipe/releases/download/demo-assets/smartpipe-teaser-v2.gif)](https://prabal-rje.github.io/smartpipe/demo/)
51
+ [![smartpipe demo - click to play with sound and controls](https://github.com/prabal-rje/smartpipe/releases/download/demo-assets/smartpipe-teaser-v3.gif)](https://prabal-rje.github.io/smartpipe/demo/)
51
52
 
52
53
  *[▶ Watch the full 70-second demo](https://prabal-rje.github.io/smartpipe/demo/) - sound, controls, no download.*
53
54
 
54
55
  ## Install
55
56
 
57
+ **macOS** - Homebrew is the happy path:
58
+
59
+ ```bash
60
+ brew install prabal-rje/tap/smartpipe
61
+ ```
62
+
63
+ **Linux** - one line (uses Homebrew if you have it, bootstraps uv otherwise;
64
+ works on macOS too):
65
+
66
+ ```bash
67
+ curl -LsSf https://prabal-rje.github.io/smartpipe/install.sh | sh
68
+ ```
69
+
70
+ **Windows**:
71
+
72
+ ```powershell
73
+ powershell -ExecutionPolicy Bypass -c "irm https://prabal-rje.github.io/smartpipe/install.ps1 | iex"
74
+ ```
75
+
76
+ Prefer your own Python tooling? Any of these works on every platform:
77
+
56
78
  ```bash
57
- # zero-install trial (or: pip install smartpipe-cli)
58
- uvx --from smartpipe-cli smartpipe
79
+ uv tool install smartpipe-cli # uv
80
+ pipx install smartpipe-cli # pipx
81
+ pip install smartpipe-cli # pip
82
+ uvx --from smartpipe-cli smartpipe # zero-install trial
59
83
  ```
60
84
 
85
+ Stay current with `smartpipe update` - it detects how smartpipe was installed
86
+ and runs that tool's own upgrade.
87
+
61
88
  ## Point it at a model
62
89
 
63
90
  ```bash
@@ -146,8 +173,8 @@ cat tickets.jsonl \
146
173
 
147
174
  # 4. group feedback by meaning, label each theme, chart it
148
175
  cat feedback.txt \
149
- | smartpipe cluster --top 8 \
150
- | smartpipe chart cluster --save themes.svg
176
+ | smartpipe cluster --explode members \
177
+ | smartpipe chart cluster --top 8 --save themes.svg
151
178
 
152
179
  # 5. cut for free with `where`, then let the model judge only what is left
153
180
  cat app.log \
@@ -167,6 +194,10 @@ smartpipe embed 'sessions/**/*.mp4' > sessions.embeddings
167
194
  smartpipe top_k 3 --near "user gives up after the coupon fails" < sessions.embeddings
168
195
  ```
169
196
 
197
+ A `.txt` on a pipe arrives one item per line; `--as file` treats the whole
198
+ file as one item ([feeding smartpipe](docs/concepts/feeding-smartpipe.md) has
199
+ the full ingestion table).
200
+
170
201
  Numbers 7 and 8 are full recipes -
171
202
  [invoice reconciliation](docs/cookbook/invoice-reconciliation.md) and
172
203
  [video RAG](docs/cookbook/video-qa.md) - two of a dozen in the
@@ -175,6 +206,21 @@ Numbers 7 and 8 are full recipes -
175
206
  New to this? The [Learn track][quickstart] starts at zero and assumes nothing, including
176
207
  what a "model" is.
177
208
 
209
+ ## Try it on real files
210
+
211
+ No corpus handy? [smartpipe-playground][playground] ships 26 MB of CC0 /
212
+ public-domain practice files - invoices, reports, photos, recordings, screen
213
+ sessions, and JSONL data:
214
+
215
+ ```bash
216
+ curl -L https://github.com/prabal-rje/smartpipe-playground/archive/refs/tags/v1.tar.gz | tar xz
217
+ cd smartpipe-playground-1
218
+
219
+ smartpipe map "Extract {vendor, invoice_number, total number}" 'invoices/*.pdf'
220
+ smartpipe filter "the customer sounds frustrated" 'recordings/*.mp3'
221
+ smartpipe top_k 3 --near "supply chain risk" 'reports/*.pdf'
222
+ ```
223
+
178
224
  ## For AI agents
179
225
 
180
226
  Driving smartpipe from an agent? [SKILL.md](SKILL.md) is the operating
@@ -245,6 +291,7 @@ lives in [`qa/`](qa/README.md). The CLI surface is a SemVer contract.
245
291
  [models]: https://prabal-rje.github.io/smartpipe/concepts/models-and-providers/
246
292
  [privacy]: https://prabal-rje.github.io/smartpipe/privacy/
247
293
  [ollama]: https://ollama.com
294
+ [playground]: https://github.com/prabal-rje/smartpipe-playground
248
295
  [map]: https://prabal-rje.github.io/smartpipe/verbs/map/
249
296
  [extend]: https://prabal-rje.github.io/smartpipe/verbs/extend/
250
297
  [filter]: https://prabal-rje.github.io/smartpipe/verbs/filter/
@@ -11,17 +11,43 @@
11
11
  Run PDFs, images, audio, video, and text through Unix verbs that understand
12
12
  their input.
13
13
 
14
- [![smartpipe demo - click to play with sound and controls](https://github.com/prabal-rje/smartpipe/releases/download/demo-assets/smartpipe-teaser-v2.gif)](https://prabal-rje.github.io/smartpipe/demo/)
14
+ [![smartpipe demo - click to play with sound and controls](https://github.com/prabal-rje/smartpipe/releases/download/demo-assets/smartpipe-teaser-v3.gif)](https://prabal-rje.github.io/smartpipe/demo/)
15
15
 
16
16
  *[▶ Watch the full 70-second demo](https://prabal-rje.github.io/smartpipe/demo/) - sound, controls, no download.*
17
17
 
18
18
  ## Install
19
19
 
20
+ **macOS** - Homebrew is the happy path:
21
+
22
+ ```bash
23
+ brew install prabal-rje/tap/smartpipe
24
+ ```
25
+
26
+ **Linux** - one line (uses Homebrew if you have it, bootstraps uv otherwise;
27
+ works on macOS too):
28
+
29
+ ```bash
30
+ curl -LsSf https://prabal-rje.github.io/smartpipe/install.sh | sh
31
+ ```
32
+
33
+ **Windows**:
34
+
35
+ ```powershell
36
+ powershell -ExecutionPolicy Bypass -c "irm https://prabal-rje.github.io/smartpipe/install.ps1 | iex"
37
+ ```
38
+
39
+ Prefer your own Python tooling? Any of these works on every platform:
40
+
20
41
  ```bash
21
- # zero-install trial (or: pip install smartpipe-cli)
22
- uvx --from smartpipe-cli smartpipe
42
+ uv tool install smartpipe-cli # uv
43
+ pipx install smartpipe-cli # pipx
44
+ pip install smartpipe-cli # pip
45
+ uvx --from smartpipe-cli smartpipe # zero-install trial
23
46
  ```
24
47
 
48
+ Stay current with `smartpipe update` - it detects how smartpipe was installed
49
+ and runs that tool's own upgrade.
50
+
25
51
  ## Point it at a model
26
52
 
27
53
  ```bash
@@ -110,8 +136,8 @@ cat tickets.jsonl \
110
136
 
111
137
  # 4. group feedback by meaning, label each theme, chart it
112
138
  cat feedback.txt \
113
- | smartpipe cluster --top 8 \
114
- | smartpipe chart cluster --save themes.svg
139
+ | smartpipe cluster --explode members \
140
+ | smartpipe chart cluster --top 8 --save themes.svg
115
141
 
116
142
  # 5. cut for free with `where`, then let the model judge only what is left
117
143
  cat app.log \
@@ -131,6 +157,10 @@ smartpipe embed 'sessions/**/*.mp4' > sessions.embeddings
131
157
  smartpipe top_k 3 --near "user gives up after the coupon fails" < sessions.embeddings
132
158
  ```
133
159
 
160
+ A `.txt` on a pipe arrives one item per line; `--as file` treats the whole
161
+ file as one item ([feeding smartpipe](docs/concepts/feeding-smartpipe.md) has
162
+ the full ingestion table).
163
+
134
164
  Numbers 7 and 8 are full recipes -
135
165
  [invoice reconciliation](docs/cookbook/invoice-reconciliation.md) and
136
166
  [video RAG](docs/cookbook/video-qa.md) - two of a dozen in the
@@ -139,6 +169,21 @@ Numbers 7 and 8 are full recipes -
139
169
  New to this? The [Learn track][quickstart] starts at zero and assumes nothing, including
140
170
  what a "model" is.
141
171
 
172
+ ## Try it on real files
173
+
174
+ No corpus handy? [smartpipe-playground][playground] ships 26 MB of CC0 /
175
+ public-domain practice files - invoices, reports, photos, recordings, screen
176
+ sessions, and JSONL data:
177
+
178
+ ```bash
179
+ curl -L https://github.com/prabal-rje/smartpipe-playground/archive/refs/tags/v1.tar.gz | tar xz
180
+ cd smartpipe-playground-1
181
+
182
+ smartpipe map "Extract {vendor, invoice_number, total number}" 'invoices/*.pdf'
183
+ smartpipe filter "the customer sounds frustrated" 'recordings/*.mp3'
184
+ smartpipe top_k 3 --near "supply chain risk" 'reports/*.pdf'
185
+ ```
186
+
142
187
  ## For AI agents
143
188
 
144
189
  Driving smartpipe from an agent? [SKILL.md](SKILL.md) is the operating
@@ -209,6 +254,7 @@ lives in [`qa/`](qa/README.md). The CLI surface is a SemVer contract.
209
254
  [models]: https://prabal-rje.github.io/smartpipe/concepts/models-and-providers/
210
255
  [privacy]: https://prabal-rje.github.io/smartpipe/privacy/
211
256
  [ollama]: https://ollama.com
257
+ [playground]: https://github.com/prabal-rje/smartpipe-playground
212
258
  [map]: https://prabal-rje.github.io/smartpipe/verbs/map/
213
259
  [extend]: https://prabal-rje.github.io/smartpipe/verbs/extend/
214
260
  [filter]: https://prabal-rje.github.io/smartpipe/verbs/filter/
@@ -22,6 +22,8 @@ Files go after the prompt (quote globs). Each path's default:
22
22
 
23
23
  - `.jsonl` / `.ndjson` → strict records, one per line; a bad row is a loud
24
24
  error naming file and line.
25
+ - `.csv` / `.tsv` → header-named records, one per row (`.tsv` cuts on tabs);
26
+ see [csv rows](#csv-rows) below.
25
27
  - everything else → one whole-file item: documents extract their text (and
26
28
  carry embedded figures to vision models), media carry their bytes.
27
29
 
@@ -30,19 +32,50 @@ Files go after the prompt (quote globs). Each path's default:
30
32
 
31
33
  ## The `--as` dial
32
34
 
33
- `--as file|lines|jsonl` overrides every default, stdin included:
35
+ `--as file|lines|jsonl|csv` overrides every default, stdin included:
34
36
 
35
37
  ```bash
36
38
  cat poem.txt | smartpipe map "translate, keep the shape" --as file
37
39
  smartpipe map "translate" 'notes/*.txt' --as lines
38
40
  smartpipe map "classify {label}" export.txt --as jsonl
41
+ cat export.txt | smartpipe map "classify {label}" --as csv
39
42
  ```
40
43
 
41
- An explicit `--as lines`/`jsonl` must hold for EVERY matched file: images
42
- refuse (no finer granularity), audio/video point at `split --by
44
+ An explicit `--as lines`/`jsonl`/`csv` must hold for EVERY matched file:
45
+ images refuse (no finer granularity), audio/video point at `split --by
43
46
  minutes/seconds`, documents point at `split --by pages` - with offender
44
47
  counts, never silent partial application.
45
48
 
49
+ ## csv rows
50
+
51
+ `--as csv` (the default for `.csv`/`.tsv` paths) reads the header row as the
52
+ field names and every later row as one record - `name,age` + `alice,31`
53
+ becomes `{"name": "alice", "age": 31}`. On stdin the header is simply the
54
+ first line. Rows stream one at a time, exactly like jsonl - a 10 GB export
55
+ never materializes in memory.
56
+
57
+ The details, all deliberate:
58
+
59
+ - **Cell coercion is int → float → string.** A cell that is a whole number
60
+ becomes an int (`31`), a decimal or scientific number becomes a float
61
+ (`2.5`, `1e3`), and anything else - empty cells included - stays the string
62
+ it was (`007x` keeps its leading zeros). `NaN`/`Infinity` spellings stay
63
+ strings; they have no JSON form.
64
+ - **`__source` carries the PHYSICAL line number.** The header is line 1, the
65
+ first data row line 2 - so `grep -n`/`sed -n` line references match the
66
+ file exactly. A quoted cell may span lines; such a row carries its FIRST
67
+ physical line.
68
+ - **Dialect by extension.** `.tsv` cuts on tabs, with or without an explicit
69
+ `--as csv`; everything else - stdin included - cuts on commas. There is no
70
+ delimiter sniffing beyond that: extensions are predictable, sniffers guess.
71
+ - **Errors are loud, jsonl-style.** A ragged row names the file, the physical
72
+ line, and both column counts; an empty file (or blank header cell, or
73
+ duplicate column name) refuses with the fix. `--as csv` on media or
74
+ documents refuses with the same signposts as `lines`/`jsonl`.
75
+
76
+ Egress is the mirror you already have: `--output csv` on the verbs that emit
77
+ records, so `csv in → csv out` round-trips.
78
+
46
79
  ## Reader mode
47
80
 
48
81
  `smartpipe PATH…` with no verb emits the crate's items as JSONL records -
@@ -217,6 +217,53 @@ account. Only the `openai` wire exists today; the key accepts
217
217
  `provider/model` so more can land behind the same seam.
218
218
 
219
219
 
220
+ ## The ocr-model role
221
+
222
+ `smartpipe config ocr-model mistral-ocr-latest` names a dedicated document
223
+ parser. When set, ingested PDFs and images run through it instead of the
224
+ local extraction ladder - page markdown becomes the item text, and a
225
+ multi-page PDF becomes one item per page (the `__source` spine carries the
226
+ page cut, exactly like `split --by pages`). Setting the role is the consent;
227
+ every parsed page is disclosed per row:
228
+
229
+ ```text
230
+ ⚠ degraded: report.pdf p.3 document → markdown (parsed by mistral/mistral-ocr-latest)
231
+ ```
232
+
233
+ The role is provider-agnostic:
234
+
235
+ - A **mistral** ref rides the dedicated `/v1/ocr` wire (needs
236
+ `MISTRAL_API_KEY`; the endpoint charges per page).
237
+ - **Any other ref** reads pages through the normal chat-vision wire with an
238
+ extract-the-text framing - `smartpipe config ocr-model ollama/llava` is a
239
+ free local OCR. For PDFs on this rung, pages with a healthy text layer
240
+ keep their locally extracted text (zero calls); only thin, image-bearing
241
+ pages (scans) go through the model.
242
+
243
+ Inside the conversion ladder, a configured `ocr-model` also outranks the
244
+ vision-chat rung for page images, so scanned documents read as text
245
+ everywhere. If a parse fails, the item falls back to the local extraction
246
+ ladder with a note - never a hard stop. `--ocr-model` (per run) >
247
+ `SMARTPIPE_OCR_MODEL` > the config key. Unset: nothing changes.
248
+
249
+ ## The media-embed-model role
250
+
251
+ `smartpipe config media-embed-model jina/jina-clip-v2` names a JOINT
252
+ text+image embedder. When set, `embed` and `top_k` route media items to it
253
+ as pixels while text items keep using `embed-model` - and a text query can
254
+ rank an image corpus, because both live in the same space.
255
+
256
+ One vector space per run is the law: if a run holds BOTH text and media
257
+ items while the two roles name different models, smartpipe refuses loudly
258
+ (vectors from two models can't be compared). The fix it names: set
259
+ `embed-model` to the joint model too, or feed media-only input. Unset, media
260
+ items keep today's behavior (native embedding when `embed-model` itself is
261
+ media-capable, the caption pivot otherwise).
262
+
263
+ `--media-embed-model` (per run) > `SMARTPIPE_MEDIA_EMBED_MODEL` > the config
264
+ key.
265
+
266
+
220
267
  ## The usage ledger
221
268
 
222
269
  `smartpipe usage` shows what the meter observed over the past hour, day, week,
@@ -15,6 +15,31 @@ With no `--output` flag, smartpipe looks at whether `stdout` is a terminal:
15
15
  So `smartpipe map "Extract {name, role}"` shows you a tidy view on screen, but the
16
16
  moment you pipe it into `jq` or a file, it becomes clean JSONL - no flags needed.
17
17
 
18
+ ### Media previews at the terminal
19
+
20
+ In the terminal view (and in [`readable`](../verbs/readable.md)), an item
21
+ carrying media gets more than its `image/png (48 KB)` summary line - the first
22
+ media part renders right under it:
23
+
24
+ - **Images** show a small color thumbnail (aspect preserved, about 40x12
25
+ cells).
26
+ - **Video** shows a 3-frame strip sampled at 10%/50%/90% of the duration -
27
+ never the first frame, which is usually a black or logo intro.
28
+ - **Audio** shows a waveform envelope (long files decode at most the first
29
+ 10 minutes).
30
+ - **Audio and video with a real file behind them** add a
31
+ `▶ play (0:42, 2.1 MB)` line - an OSC 8 hyperlink to the `file://` URL, so
32
+ a click opens your system player. Media that exists only as pipe bytes
33
+ still gets its picture, just no link.
34
+
35
+ Previews exist only where the human view does: pipes, `--output json`,
36
+ `NO_COLOR`, and `TERM=dumb` output stay byte-for-byte what they were. The
37
+ persisted kill switch:
38
+
39
+ ```bash
40
+ smartpipe config media-previews off # back to summary lines only
41
+ ```
42
+
18
43
  ## Explicit formats
19
44
 
20
45
  | `--output` | What you get |