manyruns 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. manyruns-0.1.0/.gitignore +119 -0
  2. manyruns-0.1.0/CHANGELOG.md +43 -0
  3. manyruns-0.1.0/LICENSE +21 -0
  4. manyruns-0.1.0/PKG-INFO +430 -0
  5. manyruns-0.1.0/README.md +367 -0
  6. manyruns-0.1.0/manyruns/__init__.py +28 -0
  7. manyruns-0.1.0/manyruns/adapters/__init__.py +14 -0
  8. manyruns-0.1.0/manyruns/adapters/pyrovelocity_adapter.py +82 -0
  9. manyruns-0.1.0/manyruns/admit.py +166 -0
  10. manyruns-0.1.0/manyruns/agents.py +462 -0
  11. manyruns-0.1.0/manyruns/aligned.py +77 -0
  12. manyruns-0.1.0/manyruns/app.py +2369 -0
  13. manyruns-0.1.0/manyruns/artifacts.py +227 -0
  14. manyruns-0.1.0/manyruns/catalog.py +453 -0
  15. manyruns-0.1.0/manyruns/commands.py +196 -0
  16. manyruns-0.1.0/manyruns/configs/dataset/README.md +35 -0
  17. manyruns-0.1.0/manyruns/configs/dataset/arch_sharp.yaml +16 -0
  18. manyruns-0.1.0/manyruns/configs/dataset/arch_soft.yaml +16 -0
  19. manyruns-0.1.0/manyruns/configs/dataset/blob_loose.yaml +16 -0
  20. manyruns-0.1.0/manyruns/configs/dataset/blob_tight.yaml +16 -0
  21. manyruns-0.1.0/manyruns/configs/dataset/gaussian_blob.yaml +13 -0
  22. manyruns-0.1.0/manyruns/configs/dataset/pbmc3k.yaml +83 -0
  23. manyruns-0.1.0/manyruns/configs/dataset/saddlesurface.yaml +13 -0
  24. manyruns-0.1.0/manyruns/configs/dataset/swissroll.yaml +13 -0
  25. manyruns-0.1.0/manyruns/configs/dataset/synthetic_timecourse.yaml +44 -0
  26. manyruns-0.1.0/manyruns/configs/dataset/torus.yaml +13 -0
  27. manyruns-0.1.0/manyruns/configs/dataset/torus_noisy.yaml +16 -0
  28. manyruns-0.1.0/manyruns/configs/dataset/torus_tight.yaml +16 -0
  29. manyruns-0.1.0/manyruns/configs/dataset/tree_narrow.yaml +16 -0
  30. manyruns-0.1.0/manyruns/configs/dataset/tree_wide.yaml +16 -0
  31. manyruns-0.1.0/manyruns/configs/metrics/default.yaml +202 -0
  32. manyruns-0.1.0/manyruns/configs/recipe/archetypes.yaml +63 -0
  33. manyruns-0.1.0/manyruns/configs/recipe/cflows.yaml +101 -0
  34. manyruns-0.1.0/manyruns/configs/recipe/cluster.yaml +54 -0
  35. manyruns-0.1.0/manyruns/configs/recipe/contrast.yaml +65 -0
  36. manyruns-0.1.0/manyruns/configs/recipe/embed.yaml +81 -0
  37. manyruns-0.1.0/manyruns/configs/recipe/markers.yaml +47 -0
  38. manyruns-0.1.0/manyruns/configs/recipe/preprocess.yaml +91 -0
  39. manyruns-0.1.0/manyruns/configs/recipe/pseudotime.yaml +61 -0
  40. manyruns-0.1.0/manyruns/configs/recipe/qc.yaml +44 -0
  41. manyruns-0.1.0/manyruns/configs/recipe/sandbox.yaml +56 -0
  42. manyruns-0.1.0/manyruns/configs/recipe/traced.yaml +45 -0
  43. manyruns-0.1.0/manyruns/configs/serving/local.yaml +13 -0
  44. manyruns-0.1.0/manyruns/configs/serving/modal.yaml +4 -0
  45. manyruns-0.1.0/manyruns/configs/tool/locks/pyrovelocity-0.4.5-macos-arm64.lock +3920 -0
  46. manyruns-0.1.0/manyruns/configs/tool/pyrovelocity.yaml +80 -0
  47. manyruns-0.1.0/manyruns/core.py +295 -0
  48. manyruns-0.1.0/manyruns/datasetfetch.py +195 -0
  49. manyruns-0.1.0/manyruns/decisions.py +198 -0
  50. manyruns-0.1.0/manyruns/devices.py +77 -0
  51. manyruns-0.1.0/manyruns/env.py +38 -0
  52. manyruns-0.1.0/manyruns/experiment.py +364 -0
  53. manyruns-0.1.0/manyruns/explore_core.py +104 -0
  54. manyruns-0.1.0/manyruns/figspec.py +473 -0
  55. manyruns-0.1.0/manyruns/figures.py +168 -0
  56. manyruns-0.1.0/manyruns/harness/README.md +126 -0
  57. manyruns-0.1.0/manyruns/harness/__init__.py +165 -0
  58. manyruns-0.1.0/manyruns/harness/__main__.py +459 -0
  59. manyruns-0.1.0/manyruns/harness/agent_tools.py +75 -0
  60. manyruns-0.1.0/manyruns/harness/agents.py +68 -0
  61. manyruns-0.1.0/manyruns/harness/configs.py +273 -0
  62. manyruns-0.1.0/manyruns/harness/data_acquire.py +442 -0
  63. manyruns-0.1.0/manyruns/harness/display.py +454 -0
  64. manyruns-0.1.0/manyruns/harness/example_config.yaml +18 -0
  65. manyruns-0.1.0/manyruns/harness/interface.py +149 -0
  66. manyruns-0.1.0/manyruns/harness/labeler.py +148 -0
  67. manyruns-0.1.0/manyruns/harness/runner.py +247 -0
  68. manyruns-0.1.0/manyruns/harness/storage.py +124 -0
  69. manyruns-0.1.0/manyruns/inspected.py +146 -0
  70. manyruns-0.1.0/manyruns/installation.py +19 -0
  71. manyruns-0.1.0/manyruns/intent.py +112 -0
  72. manyruns-0.1.0/manyruns/measurements.py +8 -0
  73. manyruns-0.1.0/manyruns/modes.py +141 -0
  74. manyruns-0.1.0/manyruns/narrate.py +1561 -0
  75. manyruns-0.1.0/manyruns/outcomes.py +25 -0
  76. manyruns-0.1.0/manyruns/pipeline/__init__.py +58 -0
  77. manyruns-0.1.0/manyruns/pipeline/bounds.py +185 -0
  78. manyruns-0.1.0/manyruns/pipeline/external.py +254 -0
  79. manyruns-0.1.0/manyruns/pipeline/frame.py +127 -0
  80. manyruns-0.1.0/manyruns/pipeline/io.py +334 -0
  81. manyruns-0.1.0/manyruns/pipeline/loading.py +900 -0
  82. manyruns-0.1.0/manyruns/pipeline/mioflow.py +363 -0
  83. manyruns-0.1.0/manyruns/pipeline/null.py +98 -0
  84. manyruns-0.1.0/manyruns/pipeline/prep.py +409 -0
  85. manyruns-0.1.0/manyruns/pipeline/probes.py +95 -0
  86. manyruns-0.1.0/manyruns/pipeline/runner.py +2107 -0
  87. manyruns-0.1.0/manyruns/pipeline/steps.py +1011 -0
  88. manyruns-0.1.0/manyruns/pipeline/stubs.py +119 -0
  89. manyruns-0.1.0/manyruns/pipeline/suite.py +450 -0
  90. manyruns-0.1.0/manyruns/qc.py +160 -0
  91. manyruns-0.1.0/manyruns/registry.py +102 -0
  92. manyruns-0.1.0/manyruns/score.py +207 -0
  93. manyruns-0.1.0/manyruns/serving.py +284 -0
  94. manyruns-0.1.0/manyruns/session.py +733 -0
  95. manyruns-0.1.0/manyruns/shell.py +1303 -0
  96. manyruns-0.1.0/manyruns/store.py +151 -0
  97. manyruns-0.1.0/manyruns/toolchain.py +324 -0
  98. manyruns-0.1.0/manyruns/trace.py +215 -0
  99. manyruns-0.1.0/manyruns/tui/__init__.py +35 -0
  100. manyruns-0.1.0/manyruns/tui/app.py +1047 -0
  101. manyruns-0.1.0/manyruns/tui/colorby.py +156 -0
  102. manyruns-0.1.0/manyruns/tui/dropwatch.py +238 -0
  103. manyruns-0.1.0/manyruns/tui/figure.py +571 -0
  104. manyruns-0.1.0/manyruns/tui/find.py +619 -0
  105. manyruns-0.1.0/manyruns/tui/gate.py +223 -0
  106. manyruns-0.1.0/manyruns/tui/images.py +265 -0
  107. manyruns-0.1.0/manyruns/tui/ledger.py +457 -0
  108. manyruns-0.1.0/manyruns/tui/manyruns.tcss +66 -0
  109. manyruns-0.1.0/manyruns/tui/params.py +123 -0
  110. manyruns-0.1.0/manyruns/tui/roster.py +650 -0
  111. manyruns-0.1.0/manyruns/tui/run.py +2295 -0
  112. manyruns-0.1.0/manyruns/tui/samplefetch.py +324 -0
  113. manyruns-0.1.0/manyruns/tui/search.py +521 -0
  114. manyruns-0.1.0/manyruns/tui/state.py +1047 -0
  115. manyruns-0.1.0/manyruns/tui/theme.py +53 -0
  116. manyruns-0.1.0/manyruns/tune.py +579 -0
  117. manyruns-0.1.0/manyruns/verbs.py +42 -0
  118. manyruns-0.1.0/manyruns/vocab.py +1122 -0
  119. manyruns-0.1.0/manyruns/watch.py +230 -0
  120. manyruns-0.1.0/pyproject.toml +227 -0
  121. manyruns-0.1.0/tests/conftest.py +66 -0
  122. manyruns-0.1.0/tests/fixtures/acquire_manifest.tsv +7 -0
  123. manyruns-0.1.0/tests/fixtures/eb/matrix.h5ad +1 -0
  124. manyruns-0.1.0/tests/harness/__init__.py +2 -0
  125. manyruns-0.1.0/tests/harness/test_chat_cli.py +137 -0
  126. manyruns-0.1.0/tests/harness/test_data_acquire.py +187 -0
  127. manyruns-0.1.0/tests/harness/test_data_acquire_stack.py +106 -0
  128. manyruns-0.1.0/tests/harness/test_phase1_runner.py +74 -0
  129. manyruns-0.1.0/tests/harness/test_phase2_display.py +121 -0
  130. manyruns-0.1.0/tests/harness/test_phase3_labeler.py +120 -0
  131. manyruns-0.1.0/tests/harness/test_phase4_storage.py +153 -0
  132. manyruns-0.1.0/tests/harness/test_phase5_cli.py +195 -0
  133. manyruns-0.1.0/tests/harness/test_prompt_cli.py +37 -0
  134. manyruns-0.1.0/tests/learners.py +4 -0
  135. manyruns-0.1.0/tests/public_safety.py +63 -0
  136. manyruns-0.1.0/tests/test_abandoned_finalization.py +87 -0
  137. manyruns-0.1.0/tests/test_admit_and_store.py +138 -0
  138. manyruns-0.1.0/tests/test_agents.py +253 -0
  139. manyruns-0.1.0/tests/test_agents_ask.py +195 -0
  140. manyruns-0.1.0/tests/test_aligned.py +109 -0
  141. manyruns-0.1.0/tests/test_analysis_readouts.py +718 -0
  142. manyruns-0.1.0/tests/test_analysis_selection.py +139 -0
  143. manyruns-0.1.0/tests/test_app_eb_sample.py +62 -0
  144. manyruns-0.1.0/tests/test_app_explore.py +235 -0
  145. manyruns-0.1.0/tests/test_app_init.py +115 -0
  146. manyruns-0.1.0/tests/test_app_open.py +283 -0
  147. manyruns-0.1.0/tests/test_apply_step.py +901 -0
  148. manyruns-0.1.0/tests/test_artifacts.py +210 -0
  149. manyruns-0.1.0/tests/test_base_install.py +101 -0
  150. manyruns-0.1.0/tests/test_before_camera.py +417 -0
  151. manyruns-0.1.0/tests/test_bounds.py +267 -0
  152. manyruns-0.1.0/tests/test_categorical_colour_key.py +204 -0
  153. manyruns-0.1.0/tests/test_check.py +379 -0
  154. manyruns-0.1.0/tests/test_cli_live_view.py +193 -0
  155. manyruns-0.1.0/tests/test_cli_sample_fetch.py +132 -0
  156. manyruns-0.1.0/tests/test_color_by.py +298 -0
  157. manyruns-0.1.0/tests/test_commands.py +183 -0
  158. manyruns-0.1.0/tests/test_condition_as_time.py +128 -0
  159. manyruns-0.1.0/tests/test_contrast.py +159 -0
  160. manyruns-0.1.0/tests/test_core.py +127 -0
  161. manyruns-0.1.0/tests/test_dataset_fetch.py +722 -0
  162. manyruns-0.1.0/tests/test_decisions.py +264 -0
  163. manyruns-0.1.0/tests/test_demo_walk.py +736 -0
  164. manyruns-0.1.0/tests/test_devices.py +67 -0
  165. manyruns-0.1.0/tests/test_display_routes.py +843 -0
  166. manyruns-0.1.0/tests/test_distribution_contents.py +78 -0
  167. manyruns-0.1.0/tests/test_doc_references.py +32 -0
  168. manyruns-0.1.0/tests/test_dotenv.py +34 -0
  169. manyruns-0.1.0/tests/test_engine_extras.py +172 -0
  170. manyruns-0.1.0/tests/test_engine_modes.py +74 -0
  171. manyruns-0.1.0/tests/test_engine_path.py +116 -0
  172. manyruns-0.1.0/tests/test_env.py +168 -0
  173. manyruns-0.1.0/tests/test_execution_routes.py +234 -0
  174. manyruns-0.1.0/tests/test_experiment.py +331 -0
  175. manyruns-0.1.0/tests/test_explore_core.py +64 -0
  176. manyruns-0.1.0/tests/test_extension_contract.py +126 -0
  177. manyruns-0.1.0/tests/test_figspec.py +518 -0
  178. manyruns-0.1.0/tests/test_figure_pane.py +202 -0
  179. manyruns-0.1.0/tests/test_frame.py +177 -0
  180. manyruns-0.1.0/tests/test_front_door.py +522 -0
  181. manyruns-0.1.0/tests/test_gene_axis.py +454 -0
  182. manyruns-0.1.0/tests/test_gene_axis_fact.py +187 -0
  183. manyruns-0.1.0/tests/test_gene_axis_reaches_the_engine.py +88 -0
  184. manyruns-0.1.0/tests/test_group_narration.py +139 -0
  185. manyruns-0.1.0/tests/test_gvector_schema.py +196 -0
  186. manyruns-0.1.0/tests/test_identity.py +86 -0
  187. manyruns-0.1.0/tests/test_inspected.py +214 -0
  188. manyruns-0.1.0/tests/test_install_surfaces.py +467 -0
  189. manyruns-0.1.0/tests/test_label_wiring.py +91 -0
  190. manyruns-0.1.0/tests/test_labels_reach_the_run.py +186 -0
  191. manyruns-0.1.0/tests/test_ledger_location.py +42 -0
  192. manyruns-0.1.0/tests/test_ledger_primitives.py +450 -0
  193. manyruns-0.1.0/tests/test_lineage.py +759 -0
  194. manyruns-0.1.0/tests/test_live_dashboard.py +188 -0
  195. manyruns-0.1.0/tests/test_loading.py +305 -0
  196. manyruns-0.1.0/tests/test_manylatents_engine.py +231 -0
  197. manyruns-0.1.0/tests/test_mioflow_params.py +400 -0
  198. manyruns-0.1.0/tests/test_mock_record.py +64 -0
  199. manyruns-0.1.0/tests/test_model_retention.py +238 -0
  200. manyruns-0.1.0/tests/test_modes.py +90 -0
  201. manyruns-0.1.0/tests/test_named_dataset_dims.py +49 -0
  202. manyruns-0.1.0/tests/test_named_dataset_facts.py +583 -0
  203. manyruns-0.1.0/tests/test_narrate.py +124 -0
  204. manyruns-0.1.0/tests/test_narrowing_calculus.py +401 -0
  205. manyruns-0.1.0/tests/test_no_track_to_a_learner.py +44 -0
  206. manyruns-0.1.0/tests/test_null_ranks.py +165 -0
  207. manyruns-0.1.0/tests/test_offloaded_compute.py +359 -0
  208. manyruns-0.1.0/tests/test_ok_and_complete.py +218 -0
  209. manyruns-0.1.0/tests/test_order_calculus.py +312 -0
  210. manyruns-0.1.0/tests/test_pbmc3k_annotated_fixture.py +84 -0
  211. manyruns-0.1.0/tests/test_prep_steps.py +229 -0
  212. manyruns-0.1.0/tests/test_public_path.py +229 -0
  213. manyruns-0.1.0/tests/test_public_safety.py +174 -0
  214. manyruns-0.1.0/tests/test_qc_at_load.py +174 -0
  215. manyruns-0.1.0/tests/test_quiet_alignment.py +45 -0
  216. manyruns-0.1.0/tests/test_recipe_catalog.py +259 -0
  217. manyruns-0.1.0/tests/test_recipe_config.py +34 -0
  218. manyruns-0.1.0/tests/test_recipe_convention.py +357 -0
  219. manyruns-0.1.0/tests/test_record_schema.py +52 -0
  220. manyruns-0.1.0/tests/test_registry.py +41 -0
  221. manyruns-0.1.0/tests/test_release_workflow.py +57 -0
  222. manyruns-0.1.0/tests/test_run_panel.py +526 -0
  223. manyruns-0.1.0/tests/test_sample_distribution.py +125 -0
  224. manyruns-0.1.0/tests/test_score.py +94 -0
  225. manyruns-0.1.0/tests/test_serving.py +74 -0
  226. manyruns-0.1.0/tests/test_session.py +767 -0
  227. manyruns-0.1.0/tests/test_shell.py +610 -0
  228. manyruns-0.1.0/tests/test_singlecell_runtime.py +16 -0
  229. manyruns-0.1.0/tests/test_smoke.py +46 -0
  230. manyruns-0.1.0/tests/test_stack_integration.py +409 -0
  231. manyruns-0.1.0/tests/test_step_order.py +146 -0
  232. manyruns-0.1.0/tests/test_step_record.py +383 -0
  233. manyruns-0.1.0/tests/test_stubs.py +138 -0
  234. manyruns-0.1.0/tests/test_suite.py +410 -0
  235. manyruns-0.1.0/tests/test_supplied_embedding.py +172 -0
  236. manyruns-0.1.0/tests/test_synthetic_timecourse.py +216 -0
  237. manyruns-0.1.0/tests/test_tabular_inputs.py +199 -0
  238. manyruns-0.1.0/tests/test_time_coord.py +87 -0
  239. manyruns-0.1.0/tests/test_toolchain.py +255 -0
  240. manyruns-0.1.0/tests/test_tools_cli.py +73 -0
  241. manyruns-0.1.0/tests/test_trace.py +316 -0
  242. manyruns-0.1.0/tests/test_tree_fixture.py +35 -0
  243. manyruns-0.1.0/tests/test_tui_colorby.py +771 -0
  244. manyruns-0.1.0/tests/test_tui_display_integration.py +702 -0
  245. manyruns-0.1.0/tests/test_tui_dropwatch.py +231 -0
  246. manyruns-0.1.0/tests/test_tui_figure.py +380 -0
  247. manyruns-0.1.0/tests/test_tui_find.py +892 -0
  248. manyruns-0.1.0/tests/test_tui_gate.py +270 -0
  249. manyruns-0.1.0/tests/test_tui_images.py +281 -0
  250. manyruns-0.1.0/tests/test_tui_integration.py +2195 -0
  251. manyruns-0.1.0/tests/test_tui_ledger.py +758 -0
  252. manyruns-0.1.0/tests/test_tui_params.py +137 -0
  253. manyruns-0.1.0/tests/test_tui_responsiveness.py +515 -0
  254. manyruns-0.1.0/tests/test_tui_roster.py +1918 -0
  255. manyruns-0.1.0/tests/test_tui_run.py +2947 -0
  256. manyruns-0.1.0/tests/test_tui_samplefetch.py +936 -0
  257. manyruns-0.1.0/tests/test_tui_state.py +1518 -0
  258. manyruns-0.1.0/tests/test_tui_subprocess.py +173 -0
  259. manyruns-0.1.0/tests/test_tune.py +900 -0
  260. manyruns-0.1.0/tests/test_vocab.py +87 -0
  261. manyruns-0.1.0/tests/test_watch.py +240 -0
@@ -0,0 +1,119 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # secrets — never commit / machine-local
7
+ .env
8
+ .env.*
9
+ .envrc
10
+ *.so
11
+ .Python
12
+ build/
13
+ develop-eggs/
14
+ dist/
15
+ downloads/
16
+ eggs/
17
+ .eggs/
18
+ lib/
19
+ lib64/
20
+ parts/
21
+ sdist/
22
+ var/
23
+ wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+
28
+ # Virtual environments
29
+ .venv/
30
+ venv/
31
+ ENV/
32
+ env/
33
+
34
+ # IDEs
35
+ .vscode/
36
+ .idea/
37
+ *.swp
38
+ *.swo
39
+
40
+ # Written by a TOOL, into whatever directory it was launched from. `pyrovelocity`'s trainer
41
+ # opens an mlflow tracking store on import and drops `mlflow.db` + `mlruns/` in the cwd — so
42
+ # every `manyruns run` of a tool recipe leaves them in the repo root. They are a tool's
43
+ # scratch state, not this project's: nothing here reads them, and one was committed by a
44
+ # `git add -A` before this line existed (#86, removed in the commit that added it).
45
+ mlflow.db
46
+ mlruns/
47
+
48
+ # Runtime outputs
49
+ outputs/
50
+ # `artifacts.root(out_dir)` is `<out_dir>/state`. In product use out_dir is
51
+ # `outputs/<project>`, so state lands under the ignored path above — but `_run_steps`
52
+ # falls back to `ctx.get("out_dir") or "."`, so a run with no out_dir writes ./state
53
+ # into whatever directory it was launched from. Ignored here, and the fallback itself
54
+ # is a defect worth fixing rather than papering over.
55
+ state/
56
+ plots/
57
+ wandb/
58
+ logs/
59
+ *.log
60
+
61
+ # Model checkpoints
62
+ *.pt
63
+ *.pth
64
+ *.ckpt
65
+
66
+ # Data (don't commit datasets)
67
+ data/
68
+ *.h5ad
69
+ *.npy
70
+ *.npz
71
+ *.csv
72
+
73
+ # ...but always keep committed test fixtures (dep-free placeholders, e.g. the EB
74
+ # acceptance run) — they must survive the data-suffix ignores above.
75
+ !tests/fixtures/**
76
+
77
+ # OS
78
+ .DS_Store
79
+ Thumbs.db
80
+
81
+ # Hydra
82
+ .hydra/
83
+ multirun/
84
+
85
+ # Jupyter
86
+ .ipynb_checkpoints/
87
+ *.ipynb
88
+
89
+ # Keep directory structure
90
+ !experiments/expert_targets/.gitkeep
91
+ !experiments/trained_policies/.gitkeep
92
+ !experiments/results/.gitkeep
93
+ !experiments/manifests/.gitkeep
94
+ !experiments/reference_library/.gitkeep
95
+ _IMPLEMENTATION_NOTES.md
96
+ _PLUGIN_POINTS_SUMMARY.md
97
+ _CURRENT_STATUS.md
98
+ _CI_TESTING_SUMMARY.md
99
+ lightning_logs/
100
+ # harness test artifacts (DR runner saves embedding plots to cwd)
101
+ embedding_*.png
102
+ labeled.json
103
+
104
+ # local scRNA-seq datasets (e.g. EB timepoints)
105
+ scRNAseq/
106
+
107
+ # the interactive shell's drop folder — users' own data, never committed
108
+ /data/
109
+
110
+ # Claude Code — the per-programmer half only.
111
+ # `.claude/settings.json`, `.claude/skills/`, `.claude/agents/` and `.claude/commands/` are
112
+ # shared project context and stay tracked; these two are local to one machine.
113
+ # `worktrees/` holds real checkouts (2.5 GB here) and embeds git repos inside this one.
114
+ .claude/settings.local.json
115
+ .claude/worktrees/
116
+
117
+ # The decision corpus is generated data, and a run pointed at the repo root would drop one
118
+ # here. `outputs/` is already ignored; this covers an explicit `--out-dir .`.
119
+ decisions.jsonl
@@ -0,0 +1,43 @@
1
+ # Changelog
2
+
3
+ All notable changes to manyruns are documented here, following
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
+ During the open beta, the CLI and record schema can still change.
6
+
7
+ ## [Unreleased]
8
+
9
+ ### Fixed
10
+
11
+ - Installation and runtime repair guidance consistently uses uv tool installs for
12
+ the application and `uv sync` for developer checkouts, with uv's official installer
13
+ for first-time setup.
14
+
15
+ ## [0.1.0] - 2026-09-17
16
+
17
+ First public release: an open beta for macOS and Linux, Python 3.11–3.12.
18
+
19
+ ### Added
20
+
21
+ - Interactive data exploration, 11 bundled recipes, and the run → label → store
22
+ workflow, available through `manyruns`.
23
+ - Run and decision records carry `schema_version`; missing versions read as 1.
24
+ - Public install instructions, contribution and community guides, and citation metadata.
25
+ - Verified wheel and sdist builds with PyPI trusted publishing through GitHub Actions.
26
+
27
+ ### Changed
28
+
29
+ - The harness no longer bundles a default dataset manifest; provide one explicitly or
30
+ set `MANYRUNS_ACQUIRE_MANIFEST`.
31
+
32
+ - Mock runs record run identity and step outcomes as well as their invented results.
33
+ - `.env` is read only from the working directory and no longer overrides exported variables.
34
+ - Dependency floors require the published single-cell and trajectory runtime modules.
35
+
36
+ ### Fixed
37
+
38
+ - Tabular `.csv` and `.tsv` inputs load instead of crashing.
39
+ - An explicit seed of 0 is preserved.
40
+ - Displayed figures survive tuning renames and file changes without crashing the TUI.
41
+
42
+ [Unreleased]: https://github.com/latent-reasoning-works/manyruns/compare/v0.1.0...HEAD
43
+ [0.1.0]: https://github.com/latent-reasoning-works/manyruns/releases/tag/v0.1.0
manyruns-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Latent Reasoning Works and the manyruns contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,430 @@
1
+ Metadata-Version: 2.5
2
+ Name: manyruns
3
+ Version: 0.1.0
4
+ Summary: An environment for computational biology analyses that records every run, driven the same way by people and agents.
5
+ Project-URL: Homepage, https://github.com/latent-reasoning-works/manyruns
6
+ Project-URL: Source, https://github.com/latent-reasoning-works/manyruns
7
+ Project-URL: Issues, https://github.com/latent-reasoning-works/manyruns/issues
8
+ Project-URL: Changelog, https://github.com/latent-reasoning-works/manyruns/blob/main/CHANGELOG.md
9
+ Author-email: César Miguel Valdez Córdova <cesar.valdez@mila.quebec>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: agents,computational biology,dimensionality reduction,provenance,reproducibility,single-cell
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: Operating System :: MacOS
17
+ Classifier: Operating System :: POSIX :: Linux
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
22
+ Requires-Python: <3.13,>=3.11
23
+ Requires-Dist: anndata
24
+ Requires-Dist: hydra-core>=1.3.0
25
+ Requires-Dist: manylatents-omics[singlecell]>=0.1.3
26
+ Requires-Dist: manylatents>=0.1.7
27
+ Requires-Dist: matplotlib
28
+ Requires-Dist: numpy
29
+ Requires-Dist: omegaconf>=2.3.0
30
+ Requires-Dist: pandas
31
+ Requires-Dist: phate
32
+ Requires-Dist: python-dotenv>=1.0
33
+ Requires-Dist: questionary>=2.0
34
+ Requires-Dist: rich>=13.0
35
+ Requires-Dist: scikit-learn
36
+ Requires-Dist: scipy
37
+ Requires-Dist: statsmodels
38
+ Requires-Dist: textual-image>=0.8
39
+ Requires-Dist: textual>=8.0
40
+ Provides-Extra: agents
41
+ Requires-Dist: anthropic>=0.40; extra == 'agents'
42
+ Requires-Dist: manyagents>=0.0.1; extra == 'agents'
43
+ Provides-Extra: datasets
44
+ Provides-Extra: dev
45
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
46
+ Requires-Dist: ruff<0.12,>=0.11; extra == 'dev'
47
+ Provides-Extra: engine
48
+ Provides-Extra: harness
49
+ Requires-Dist: anndata>=0.9; extra == 'harness'
50
+ Requires-Dist: click>=8.0; extra == 'harness'
51
+ Requires-Dist: manylatents[omics]; extra == 'harness'
52
+ Requires-Dist: matplotlib>=3.5; extra == 'harness'
53
+ Requires-Dist: numpy; extra == 'harness'
54
+ Requires-Dist: pillow>=10.0; extra == 'harness'
55
+ Requires-Dist: pyyaml>=6.0; extra == 'harness'
56
+ Requires-Dist: rich>=13.0; extra == 'harness'
57
+ Requires-Dist: scanpy>=1.9; extra == 'harness'
58
+ Requires-Dist: scikit-learn; extra == 'harness'
59
+ Requires-Dist: statsmodels; extra == 'harness'
60
+ Requires-Dist: wandb>=0.15; extra == 'harness'
61
+ Provides-Extra: real
62
+ Description-Content-Type: text/markdown
63
+
64
+ <div align="center">
65
+
66
+ <pre>
67
+ △ ∿ ◇ · ∴ ○ □ ◇
68
+ ∿ ∴ · ∿ ∴ · ∿ ∴ ──▶ ∴ · ◈ ──▶ ◇(λ)
69
+ ○ ∴ · □ ∿ ◇ △ ◈
70
+
71
+ m a n y r u n s
72
+
73
+ load. assume. run. repeat.
74
+ </pre>
75
+
76
+ [![license](https://img.shields.io/badge/license-MIT-F59E0B.svg)](LICENSE)
77
+ [![python](https://img.shields.io/badge/python-3.11–3.12-F59E0B.svg)](https://www.python.org)
78
+ [![uv](https://img.shields.io/badge/pkg-uv-F59E0B.svg)](https://docs.astral.sh/uv/)
79
+
80
+ </div>
81
+
82
+ ---
83
+
84
+ **Manyruns is the harness** for the [Latent Reasoning Works](https://github.com/latent-reasoning-works)
85
+ geometry stack — the system that orchestrates a run, calls the tools, stores the artifacts, and
86
+ evaluates the result. The compute lives one layer down
87
+ ([manylatents](https://github.com/latent-reasoning-works/manylatents)); this repo owns the
88
+ **workflow, the config layer, and the distribution**.
89
+
90
+ **Open beta.** The CLI and record schema can still change. Report problems in
91
+ [GitHub issues](https://github.com/latent-reasoning-works/manyruns/issues), with
92
+ `manyruns --version`, your platform, and a small reproduction.
93
+
94
+ **Supported platforms:** macOS and Linux, Python 3.11–3.12; Windows is unsupported because
95
+ a required single-cell dependency (`scikit-misc`) ships no Windows wheels.
96
+
97
+ Three ways to use it:
98
+
99
+ - **Just run `manyruns`** → an interactive app: it reads your data, tells you what it sees,
100
+ offers the analyses it can *honestly* run, executes with a live trace, and explains the
101
+ result in plain English. Pick a sample or drop your own files in the data folder.
102
+ (See [the app](#the-interactive-app).)
103
+ - **Explore one dataset** → paste a path, get an embedding, a geometry read-out, and a
104
+ written summary. `manyruns run <data>`.
105
+ - **Sweep many** → author a catalog of *recipes* (workflows) and *datasets*, run every
106
+ recipe over every dataset, and rank which geometric metrics actually separate the
107
+ workflows. The `experiment` harness.
108
+
109
+ New here? Start with the install below, then open `manyruns`.
110
+
111
+ Each working directory has one run ledger at `outputs/index.jsonl`, with artifacts under `outputs/<project>/`.
112
+
113
+ ## install
114
+
115
+ **Quickstart — once published to PyPI.** Install [uv](https://docs.astral.sh/uv/getting-started/installation/), then:
116
+
117
+ ```sh
118
+ uv tool install --python 3.12 manyruns
119
+ manyruns
120
+ ```
121
+
122
+ `uv tool upgrade manyruns` updates an installed tool in place (keeping its extras); `sh packaging/install.sh` reinstalls the base tool from scratch, which drops any extras you added.
123
+
124
+ If you do not have uv, use [uv's official installer](https://docs.astral.sh/uv/getting-started/installation/)
125
+ or follow the [setup details](#setup-details) below, then run the tool install command above.
126
+
127
+ Alternatively, install from the public repository (requires [Git](https://git-scm.com/downloads)):
128
+
129
+ ```sh
130
+ uv tool install --python 3.12 --force git+https://github.com/latent-reasoning-works/manyruns
131
+ manyruns
132
+ ```
133
+
134
+ ### Setup details
135
+
136
+ If `uv` is absent on macOS or Linux, use its official installer:
137
+
138
+ ```sh
139
+ curl -LsSf https://astral.sh/uv/install.sh | sh
140
+ ```
141
+
142
+ Open a **new terminal** or activate the PATH printed by the installer. If installation
143
+ succeeds but `manyruns` is not found, run `uv tool update-shell` and open a new terminal.
144
+ `uv tool dir --bin` shows where the commands were installed. Installation and metric
145
+ computation time depend on your machine, data, and dependencies.
146
+
147
+ `uv tool install` creates an isolated tool environment with globally invokable commands.
148
+ `uv sync` prepares the current developer checkout; run its commands through `uv run`.
149
+ For development, use `uv sync --extra harness --extra dev`; include **all already used
150
+ extras**, such as `--extra agents`, on subsequent syncs. See [CONTRIBUTING.md](CONTRIBUTING.md).
151
+
152
+ From a checkout, `make install` installs its **committed HEAD** through a local Git URL;
153
+ uncommitted edits are excluded. `make install-public` repairs an installed tool from the
154
+ public repository. `make demo` runs swissroll with the manylatents engine and the embed
155
+ recipe. `make test` and `make lint` use the checkout's development environment.
156
+
157
+ `sh packaging/install.sh` also installs from the public repository. It bootstraps uv if
158
+ absent, then checks `manyruns --version` or prints PATH advice. No organisation access
159
+ or GitHub login is required.
160
+
161
+ **The compute is a base dependency.** The metadata requests
162
+ `manylatents-omics[singlecell]`, including scanpy, because bare omics does not supply the
163
+ single-cell runtime. Python 3.12 is recommended within the supported range.
164
+
165
+ A Git tool install resolves the declared dependencies; it does not inherit this checkout's
166
+ `tool.uv.sources` or `uv.lock`. `manyruns --version` reports the installed version and Git
167
+ revision when available; Git provenance is stored in the tool's `direct_url.json`.
168
+ The release workflow verifies the built wheel and a wheel rebuilt from the sdist in clean
169
+ environments before publishing.
170
+
171
+ | install | pulls | unlocks |
172
+ |---|---|---|
173
+ | *(base)* | phate, manylatents, manylatents-omics[singlecell], scanpy, scikit-learn, scipy, statsmodels, matplotlib, anndata, textual-image | 11 bundled recipes, the metric suite, terminal figures (`--engine manylatents`); available analyses depend on the data |
174
+ | `[harness]` | manylatents[omics], scanpy, wandb | the acquire shim + the metric sweep |
175
+ | `[agents]` | manyagents>=0.0.1, anthropic (from PyPI) | the agentic **chat / prompt** stream |
176
+ | `[dev]` | pytest, ruff | the test suite |
177
+
178
+ `[real]`, `[datasets]` and `[engine]` still parse and carry nothing — deprecated no-op
179
+ aliases. To install the harness extra from PyPI once published:
180
+
181
+ ```sh
182
+ uv tool install --python 3.12 --force "manyruns[harness]"
183
+ ```
184
+
185
+ The agents extra installs from PyPI too, with no repository access required:
186
+
187
+ ```sh
188
+ uv tool install --python 3.12 --force "manyruns[agents]"
189
+ ```
190
+
191
+ ## the model
192
+
193
+ Three things, three axes — kept apart on purpose (see [CLAUDE.md](CLAUDE.md)):
194
+
195
+ - **recipe** — *what runs*: a named, ordered list of steps. Each step declares a `group`
196
+ (`latent` embedding · `lightning` trained step · `analysis` in-process read-out) and feeds
197
+ its embedding to the next. Recipes live in `manyruns/configs/recipe/*.yaml`.
198
+ - **dataset** — *what it runs on*: a handle (a manylatents name or a file path) plus a
199
+ **ground-truth `shape`** (`manifold` · `clusters` · `time-course` · `case-control` · …).
200
+ In `manyruns/configs/dataset/*.yaml`.
201
+ - **engine** — *who computes*: `manylatents` (the real DR/trajectory engine) · `mock` (fake,
202
+ no deps, never reads your data). A backend swap for one verb — run a recipe → a **g-vector**
203
+ (a dict of named geometric scalars). It is *not* how you add a new capability: a new tool (a
204
+ metric, a simulation) is a new step `group`, never a new engine. Two names are gone from this
205
+ list: `real` (it computed the same PHATE from the same PyPI package and could not run half
206
+ the catalogue) and the learner's (manyruns holds no track to a learner — see the architecture
207
+ below).
208
+
209
+ *Where* it runs (laptop / GPU / SLURM) is a separate concern the dispatcher owns.
210
+
211
+ ## the interactive app
212
+
213
+ Run `manyruns` with no arguments to open the data roster. Pick a dataset, inspect what it
214
+ contains, then choose an analysis.
215
+
216
+ - **Drop folder.** The destination is `$MANYRUNS_DATA_DIR` when set, otherwise an
217
+ existing `./data`, otherwise `~/.manyruns/data`. Launch creates the chosen folder.
218
+ Without an environment override, both existing `./data` and `~/.manyruns/data` folders
219
+ are read; the chosen destination wins a filename clash. An override reads only that folder.
220
+ - **Live roster.** Drop a file in while the app is open. The roster polls once a second and
221
+ waits for two stable observations before inspecting a new or changed copy. `ctrl+r`
222
+ requests an immediate rescan with the same settling rule; returning to the roster also
223
+ refreshes it. Your filter and selection are preserved when other files arrive.
224
+ - **Samples.** No .h5ad files are bundled in Git or the wheel. Generators such as `swissroll`
225
+ and `synthetic_timecourse` create data locally. An absent `pbmc3k` row stays visible:
226
+ its first explicit selection offers **Fetch / Back**, with size (about 5.6 MB) and
227
+ destination. A CLI run of the absent sample also explicitly fetches it. The download
228
+ checks the YAML's `sha256` and byte count in a temporary file before publishing it into
229
+ the drop folder. A mismatch refuses and removes the partial download. Later uses read
230
+ the local file and work offline. Offline first use gives the filename, URL and destination:
231
+ download `pbmc3k_raw.h5ad` from
232
+ <https://exampledata.scverse.org/scanpy/pbmc3k_raw.h5ad> and place it in the chosen drop
233
+ folder. `manyruns check` validates declarations, never downloads, and does not tell you
234
+ whether a sample file is present. The roster marks missing samples and offers **Fetch**
235
+ when a download is available.
236
+ - **Available analyses.** The menu offers what the data can support. A trajectory on data
237
+ with no time axis is refused with an explanation. PCA component requests above a named
238
+ generator's feature count are clamped to the available dimensions and reported in the run.
239
+ - **No LLM required.** Intent is rule-based; a one-call Anthropic router is an optional
240
+ upgrade behind the `[agents]` extra.
241
+
242
+ **Repeated attempts.** Press `esc` to open **Run again?**, then choose **Run again** to
243
+ return to the ledger with the same recipe selected. Choose the analysis again to start a
244
+ fresh run. If you have an answer draft, the first Escape clears it; press Escape again to
245
+ leave. Leaving an unfinished run closes tuning: an in-flight step or measurement may finish,
246
+ but later steps and final metrics that have not started are skipped. Once that work returns,
247
+ the run is recorded as incomplete. Measurements already underway are retained.
248
+
249
+ A new attempt using the same output directory waits until the previous run finishes.
250
+ The app stays responsive and shows
251
+ `waiting for the previous run to finish · esc cancels this start`.
252
+ Escape cancels the queued start; quitting cancels it too. During normal finalization, the
253
+ run screen shows `measuring geometry… final metrics are running; duration depends on dataset and machine`
254
+ with elapsed time until the run finishes.
255
+
256
+ Prefer one command? The `run` / `check` / sweep verbs below use the same tools.
257
+
258
+ ## run
259
+
260
+ ```bash
261
+ manyruns run swissroll --engine manylatents --project demo --smoke
262
+ # → outputs/demo/summary.md + outputs/demo/plots/*.png
263
+
264
+ manyruns run /path/to/counts.h5ad --project run1 # your file; the engine is the default
265
+ manyruns run swissroll --engine mock --project smoke # $0, no stack
266
+ ```
267
+
268
+ The data arg accepts **a path or a name** (auto-detected). The recipe is **auto-selected
269
+ from the data's shape** — a time axis → `cflows` (PHATE → MIOFlow → Granger), two conditions
270
+ → `contrast` (separation + composition), else `embed`. Force one with `--recipe <name>`;
271
+ `--smoke` runs MIOFlow as a single-batch check instead of the 50-epoch train.
272
+
273
+ Choose a metadata column for display with repeatable `--color-by`:
274
+
275
+ ```sh
276
+ manyruns run synthetic_timecourse --recipe embed --color-by timepoint
277
+ manyruns run /path/to/annotated.h5ad --recipe embed --color-by cell_type --color-by score
278
+ ```
279
+
280
+ The first example generates a time course locally with a `timepoint` column; accept the
281
+ normal project-name default/prompt or add `--project NAME`. The second uses columns in your
282
+ own annotated file. Each chosen column gets its own scatter PNG. Colour choice changes
283
+ only the display, leaving analysis labels and results unchanged. Raw pbmc3k has no obs metadata
284
+ to choose from.
285
+
286
+ In the TUI, F7/F8 navigate the run's figure strip; `f` opens the full-screen viewer, where
287
+ left/right arrows navigate. Press `c` on either the run screen or the full-screen viewer
288
+ to pick a metadata column by click or Enter. Recolouring needs the dataset source and a
289
+ saved figure spec; while the run is active, both screens say
290
+ `finish this run before recolouring`. Each choice writes a new view, preserves the original,
291
+ and stays in the run's figure strip after returning from the viewer. Missing or unreadable
292
+ sources and datasets without metadata show an explanation.
293
+
294
+ Press `s` on either screen to save the selected figure, including a colour view, to
295
+ `figures/` under the directory where you launched the app. With a saved figure spec,
296
+ it exports SVG, PDF and PNG at 300 dpi. When typing an answer or an ask, letter keys stay
297
+ in the text field.
298
+
299
+ Set the recorded run seed with `--seed 7`. For a MIOFlow step, manyruns passes that seed
300
+ to `MIOFlowODEFunc(init_seed=7)` **at network construction**, to the `MIOFlow` wrapper,
301
+ and to the experiment. The wrapper preserves an existing network's weights; its seed
302
+ alone cannot initialize them retroactively. Both constructor parameters describe the same
303
+ weight-initialization choice. `params: {init_seed: 7}` is refused with directions to
304
+ `--seed`, so the seed used stays consistent with the run's lineage.
305
+
306
+ `manyruns init … && manyruns explore` splits setup from the run and can step the recipe
307
+ interactively (one action at a time through `Session.step` — the same seam a
308
+ policy will drive).
309
+
310
+ ## author & check
311
+
312
+ Recipes and datasets are **directories of YAML** — the directory *is* the registry, so
313
+ adding one is adding a file. Validate before you commit:
314
+
315
+ ```bash
316
+ manyruns check
317
+ # recipes ok cflows latent:phate → lightning:mioflow → analysis:granger
318
+ # datasets ok swissroll manylatents:swissroll shape=manifold
319
+ # coverage WARN contrast no dataset can exercise it — needs a shape providing ['conditions']
320
+ ```
321
+
322
+ `check` validates every file **and** reports which recipes the current datasets can actually
323
+ exercise — a recipe no dataset can run is flagged (not silently pruned at sweep time). It
324
+ exits non-zero on a real error, so CI gates on it. This whole loop is **stackless** (mock).
325
+
326
+ Keep experimental variants out of the shipped app with `$MANYRUNS_RECIPE_DIR` /
327
+ `$MANYRUNS_DATASET_DIR` overlays — the wheel ships the blessed few; your sweep's many arms
328
+ live in your own directory.
329
+
330
+ ## the experiment
331
+
332
+ The harness runs every recipe over every dataset, collects the g-vectors into one table, and
333
+ ranks which metrics separate the workflows — the pruned metric set *is* the g-vector
334
+ definition, learned from data. It plans on the canonical runner, prunes cells the data can't
335
+ support, and parallelises with **processes**.
336
+
337
+ ```python
338
+ from manyruns import experiment as ex
339
+ from manyruns.catalog import load_recipes, load_datasets
340
+
341
+ def main():
342
+ runs = ex.plan(load_recipes(), load_datasets(), seeds=(1, 2))
343
+ rows = ex.to_rows(ex.run_all(runs, suite=["anisotropy", "lid", "trustworthiness"],
344
+ engine="manylatents", workers=4))
345
+ ex.write_table(rows, "outputs/sweep/table.csv")
346
+ print(ex.summarize(rows))
347
+
348
+ if __name__ == "__main__": # required — the pool spawns processes
349
+ main()
350
+ ```
351
+
352
+ The sweep spec and the recipe/dataset authoring briefs are pending a rewrite; the shipped
353
+ recipes under `manyruns/configs/recipe/` are the working reference.
354
+
355
+ ## architecture
356
+
357
+ ```
358
+ manyruns (this repo) the harness — distribution + workflow + the config layer it drives
359
+ │ drives
360
+ ▼
361
+ manylatents · manyagents · shop DR algorithms, metrics, orchestration, cluster infra
362
+
363
+
364
+ the learner a separate process — and it is NOT in the chain above
365
+ ╎ observes ▶ manyruns's artifacts (index.jsonl, g-vectors, decision rows)
366
+ ╎ drives ▶ manyruns's CLI, as any other user would
367
+ ```
368
+
369
+ **manyruns names no learner** — no dependency, no import, no `--engine` value, no
370
+ config. That is deliberate and it is the architecture: manyruns is the **environment** (what
371
+ is *legal*, and the *record* of what happened); the learner is what decides what is *good*.
372
+ The learner observes the environment and drives it from outside; the environment never learns
373
+ it is being driven, which is what keeps the record trustworthy — there is no privileged caller.
374
+
375
+ Manyruns is not "thin" — it is a **different kind of thing** from a learner. It *owns*
376
+ orchestration, the recipe/dataset catalog, provenance, and the tools that exist nowhere
377
+ downstream (`separation`, `composition`). It *delegates* the heavy compute (DR, metrics) and
378
+ does not train at all: the harness workflow is `run → label → store`, and it stops at the
379
+ store. The rule is **no *duplicated* compute and no *training*** — not "no compute"
380
+ (the base metadata includes the biology runtime). The full
381
+ framing and the layering rules are in [CLAUDE.md](CLAUDE.md).
382
+
383
+ ## docs
384
+
385
+ Start with the contribution guide for development, or the environment contract for the
386
+ boundary between this application and its callers.
387
+
388
+ | | |
389
+ |---|---|
390
+ | [CLAUDE.md](CLAUDE.md) | layering rules · the engine/tool/substrate guardrail · gotchas |
391
+ | [CONTRIBUTING.md](CONTRIBUTING.md) | development, tests, and releasing |
392
+ | [CHANGELOG.md](CHANGELOG.md) | user-visible changes |
393
+ | [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) | community standards and reporting |
394
+ | [docs/environment-contract.md](docs/environment-contract.md) | the environment contract |
395
+ | [docs/sidecars/](docs/sidecars/) | out-of-process sidecar tools: the pyrovelocity brief, its fixture generator and recipe |
396
+
397
+ Source comments keep their reasoning self-contained; cited documentation paths are checked
398
+ for existence by the test suite.
399
+
400
+ ## licensing and sample data
401
+
402
+ manyruns is [MIT licensed](LICENSE). Its dependencies `phate`, `graphtools`, `tasklogger`,
403
+ `leidenalg`, and `igraph` are GPL licensed; they are imported rather than bundled in the
404
+ manyruns distribution.
405
+
406
+ The `pbmc3k` sample is **10x Genomics, 3k PBMCs from a Healthy Donor**, Cell Ranger 1.1.0
407
+ (2016): [original dataset](https://www.10xgenomics.com/datasets/3-k-pbm-cs-from-a-healthy-donor-1-standard-1-1-0).
408
+ The app fetches the [Scanpy H5AD copy](https://exampledata.scverse.org/scanpy/pbmc3k_raw.h5ad)
409
+ on explicit first use. The data is not bundled with manyruns; the MIT license covers this
410
+ project's code, not third-party data.
411
+
412
+ ## status
413
+
414
+ **0.1.0 is the first public open beta.** The release is published as `manyruns` on PyPI
415
+ through GitHub Actions trusted publishing. See the [changelog](CHANGELOG.md) for changes;
416
+ CLI and record-schema compatibility are still settling during beta.
417
+
418
+ The consolidated substrate: one step loop and one g-vector schema across every engine, the
419
+ two YAML registries, `manyruns check` with coverage, the precondition calculus, and the
420
+ metric-separation harness — all runnable on the mock with no private stack, and verified
421
+ end-to-end on the real engine. Not yet done: a real `case-control` cohort (so `contrast` is
422
+ exercisable — `manyruns check` names it), the sweep on real data (the mock's numbers are
423
+ degenerate by construction), and one upstream manylatents fix (MIOFlow's `time`-key) that
424
+ lets the trajectory step drop its local shim.
425
+
426
+ ---
427
+
428
+ <p align="center">
429
+ <sub>MIT License · <a href="https://github.com/latent-reasoning-works">Latent Reasoning Works</a></sub>
430
+ </p>