loopmath 0.2.2__tar.gz → 0.2.4__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.
- {loopmath-0.2.2/src/loopmath.egg-info → loopmath-0.2.4}/PKG-INFO +39 -24
- {loopmath-0.2.2 → loopmath-0.2.4}/README.md +38 -23
- {loopmath-0.2.2 → loopmath-0.2.4}/pyproject.toml +1 -1
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/__init__.py +1 -1
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/adapters/atrium.py +1 -1
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/adapters/bb.py +1 -1
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/adapters/opencode.py +1 -1
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/adapters/orca.py +1 -1
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/adapters/otel_genai.py +1 -1
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/adapters/paseo.py +1 -1
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/belief/check_pymc.py +7 -3
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/belief/commands.py +41 -1
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/belief/design.py +5 -3
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/belief/fit.py +6 -4
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/belief/priors.py +46 -7
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/belief/state.py +4 -1
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/builder/context.py +20 -3
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/builder/predict.py +8 -1
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/cli.py +73 -30
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/cli_graph.py +28 -19
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/cli_registry.py +31 -10
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/cli_support.py +117 -4
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/e0/verb.py +16 -8
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/fit_bayes.py +57 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/dataset_build.py +2 -2
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/html_common.py +56 -25
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/html_css.py +5 -2
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/html_data.py +35 -12
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/html_force.py +9 -1
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/html_render.py +1 -1
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/html_swimlanes.py +28 -6
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/logmatch/clip.py +16 -3
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/logmatch/match.py +94 -7
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/logmatch/settle.py +7 -6
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/onboard/commands.py +24 -6
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/onboard/history.py +48 -6
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/onboard/usual.py +4 -2
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/output.py +47 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/priors/__init__.py +31 -8
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/priors/benchmarks.py +6 -1
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/priors/benchmarks.toml +7 -2
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/priors/build.py +84 -33
- loopmath-0.2.4/src/loopmath/priors/bundle/README.md +7 -0
- loopmath-0.2.4/src/loopmath/priors/bundle/e0.jsonl.gz +0 -0
- loopmath-0.2.4/src/loopmath/priors/bundle/lanes.jsonl.gz +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/priors/bundle/manifest.json +133 -42
- loopmath-0.2.4/src/loopmath/priors/bundle/rq1.jsonl.gz +0 -0
- loopmath-0.2.4/src/loopmath/priors/bundle/sweep.jsonl.gz +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/priors/commands.py +20 -12
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/priors/e0.py +8 -3
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/priors/lanes.py +15 -1
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/priors/ocpdoc.py +45 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/priors/registry.py +3 -1
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/priors/rq1.py +13 -3
- loopmath-0.2.4/src/loopmath/priors/show.py +182 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/priors/sweep.py +34 -7
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/recommend/commands.py +78 -21
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/recommend/engine.py +18 -8
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/recommend/message.py +54 -7
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/recommend/storeread.py +31 -10
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/report/terminal.py +28 -3
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/share/commands.py +45 -5
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/share/export.py +12 -3
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/skill/commands.py +34 -7
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/skill/doctor.py +9 -2
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/skill/install.py +38 -21
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/skill/skills/loopmath-import-runs/SKILL.md +2 -2
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/skill/skills/loopmath-onboard/SKILL.md +3 -1
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/skill/skills/loopmath-record-run/SKILL.md +2 -2
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/skill/skills/loopmath-update-fit/SKILL.md +2 -2
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/skill/skills/reference.md +13 -4
- loopmath-0.2.4/src/loopmath/store/budget.py +153 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/store/commands.py +166 -47
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/store/config.py +48 -3
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/store/finish.py +2 -2
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/store/fitjob.py +56 -11
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/store/home.py +68 -11
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/store/ids.py +28 -4
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/store/record.py +192 -31
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/store/report.py +18 -14
- loopmath-0.2.4/src/loopmath/store/run_names.py +45 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/store/runs.py +14 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/store/status.py +42 -10
- loopmath-0.2.4/src/loopmath/store/verify.py +106 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/surface_presentation.py +28 -2
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/types.py +9 -1
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/views/assets/builder.css +4 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/views/assets/builder.js +81 -22
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/views/assets/common.js +14 -4
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/views/assets/estimates.js +10 -5
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/views/assets/graph.js +71 -10
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/views/assets/plans.css +1 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/views/assets/plans.js +25 -5
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/views/assets/results.js +58 -19
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/views/assets/runs.js +1 -1
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/views/assets/viz.css +3 -1
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/views/assets/viz.js +19 -3
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/views/common.py +25 -1
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/views/posterior.py +140 -8
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/views/runs.py +37 -11
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/workflows/commands.py +14 -4
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/workflows/shapes.py +15 -0
- {loopmath-0.2.2 → loopmath-0.2.4/src/loopmath.egg-info}/PKG-INFO +39 -24
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath.egg-info/SOURCES.txt +5 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_adapter_services.py +1 -1
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_adapters.py +33 -1
- loopmath-0.2.4/tests/test_analyze_cli.py +112 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_cli_graph.py +54 -41
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_cli_prices.py +26 -2
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_fit.py +8 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_graph_dataset.py +3 -3
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_graph_runfile.py +6 -3
- loopmath-0.2.4/tests/test_research_cli.py +83 -0
- loopmath-0.2.4/tests/test_starting_prior.py +233 -0
- loopmath-0.2.2/src/loopmath/priors/bundle/README.md +0 -3
- loopmath-0.2.2/src/loopmath/priors/bundle/e0.jsonl.gz +0 -0
- loopmath-0.2.2/src/loopmath/priors/bundle/lanes.jsonl.gz +0 -0
- loopmath-0.2.2/src/loopmath/priors/bundle/rq1.jsonl.gz +0 -0
- loopmath-0.2.2/src/loopmath/priors/bundle/sweep.jsonl.gz +0 -0
- loopmath-0.2.2/src/loopmath/priors/show.py +0 -72
- loopmath-0.2.2/src/loopmath/store/budget.py +0 -86
- {loopmath-0.2.2 → loopmath-0.2.4}/LICENSE +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/setup.cfg +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/spec/ocp-v0.2.schema.json +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/spec/ocp-v0.schema.json +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/spec/ocp_conformance.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/__main__.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/adapter_host.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/adapters/__init__.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/adapters/base.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/adapters/bb_support.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/adapters/omp.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/adapters/omp_facts.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/adapters/omp_links.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/adapters/omp_parse.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/adapters/omp_types.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/adapters/opencode_store.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/adapters/otel_genai_graph.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/adapters/otel_genai_parse.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/adapters/otel_genai_types.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/adapters/otel_genai_usage.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/adapters/pi.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/adapters/pi_support.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/adapters/registry.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/belief/__init__.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/belief/block.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/belief/compose.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/belief/features.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/belief/forest.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/belief/gaussian.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/belief/lookahead.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/belief/outcome.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/belief/pricing.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/builder/__init__.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/builder/cli.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/builder/server.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/e0/__init__.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/e0/arms.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/e0/cli_e0.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/e0/estimate.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/e0/estimate_rework.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/e0/figures.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/e0/io.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/explain.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/fit.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/fit_assembly.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/fit_masks.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/fit_predict.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/fit_pricing.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/fit_transfer.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/gaps.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/gitwalk.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/grade.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/grade_support.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/__init__.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/artifact_git.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/artifact_join.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/artifact_kinds.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/artifacts.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/bashparse.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/bashread_ops.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/bashwrite_ops.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/bashwrites.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/cache.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/codexio.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/codexio_parse.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/codexio_scan.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/dataset.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/dataset_core.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/dataset_edges.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/dataset_nodes.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/extract.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/html_costcurve.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/labeler.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/labeler_cli.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/labeler_common.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/labeler_parse.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/labeler_pricing.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/labeler_prompt.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/labeler_prompt_build.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/labeler_prompt_dispatch.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/labeler_prompt_evidence.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/labeler_prompt_node.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/labeler_prompt_records.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/labeler_prompt_result.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/labeler_prompt_session.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/labeler_prompt_tools.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/labeler_prompt_validation.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/labeler_prompt_workflow.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/labeler_report.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/labeler_score.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/labels.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/launch.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/launch_origin.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/ocp.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/ocp_emit.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/ocp_support.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/render.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/runfile.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/runfile_export.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/runfile_finish.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/scan.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/schema.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/graph/token_completeness.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/ingest/__init__.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/ingest/base.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/ingest/claude_code.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/ingest/claude_code_support.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/ingest/codex.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/ingest/codex_support.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/ingest/ocp.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/ingest/ocp_analysis.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/ingest/ocp_artifact.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/ingest/ocp_common.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/ingest/ocp_convert.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/ingest/ocp_projection.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/logmatch/__init__.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/logmatch/artifacts.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/logmatch/costs.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/logmatch/tariff.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/ocp/__init__.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/ocp/canonical.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/ocp/commands.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/ocp/conformance.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/ocp/contractv3.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/ocp/emit.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/ocp/migrate.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/ocp/schema/ocp-v0.2.schema.json +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/ocp/schema/ocp-v0.3.schema.json +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/ocp/schema/ocp-v0.schema.json +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/ocp/version.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/onboard/__init__.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/onboard/label.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/pool.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/price.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/price_validation.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/prices.toml +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/priors/history.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/priors/reduce.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/priors/validate.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/receipts.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/recommend/__init__.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/recommend/backlog.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/recommend/curve.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/recommend/gain.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/recommend/receipts.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/recommend/search.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/recommend/stats.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/report/__init__.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/report/html.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/report/terminal_exclusions.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/report/terminal_format.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/report/terminal_read.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/research_defaults.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/research_paths.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/scoring.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/scoring_comparisons.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/scoring_predictive.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/share/__init__.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/share/import_.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/skill/__init__.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/skill/skills/loopmath/SKILL.md +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/skill/skills/loopmath-plan-task/SKILL.md +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/store/__init__.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/store/lock.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/surface.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/surface_bootstrap.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/surface_estimation.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/surface_frame.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/surface_support.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/taskmodel.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/views/__init__.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/views/assets/README.md +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/views/assets/base.css +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/views/assets/builder.html +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/views/assets/estimates.css +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/views/assets/graph.css +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/views/assets/results.css +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/views/plans.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/workflows/__init__.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/workflows/candidates.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/workflows/catalog/best_of_n.toml +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/workflows/catalog/implement_review.toml +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/workflows/catalog/plan_implement.toml +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/workflows/catalog/plan_implement_review.toml +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/workflows/catalog/solo.toml +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/workflows/catalog/swarm.toml +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/workflows/diff.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/workflows/format.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/workflows/graphview.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/workflows/ids.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/workflows/infer.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/workflows/models.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath/workflows/ocp.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath.egg-info/dependency_links.txt +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath.egg-info/entry_points.txt +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath.egg-info/requires.txt +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/src/loopmath.egg-info/top_level.txt +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_adapter_atrium.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_adapter_bb.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_adapter_omp.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_adapter_opencode.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_adapter_opencode_output_tokens.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_adapter_orca.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_adapter_otel_genai.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_adapter_paseo.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_adapters_pi.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_arms.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_cli_help_lists.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_cli_labeler.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_cli_main_module.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_cli_plan_hidden.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_cli_startup.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_color_proof.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_duplicate_guards.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_estimate.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_explain.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_gaps.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_gitwalk.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_grade.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_graph_artifact_recording.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_graph_artifacts.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_graph_bashwrites.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_graph_cache.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_graph_codexio.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_graph_extract.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_graph_glue.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_graph_html.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_graph_labeler.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_graph_labeler_evidence_matrix.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_graph_launch.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_graph_ocp.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_graph_render.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_graph_schema.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_home_guard.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_html.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_ingest.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_ingest_claude_code.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_ingest_codex.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_ingest_ocp.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_io.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_not_run_summary.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_ocp_conformance.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_ocp_golden.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_ocp_open_enums.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_ocp_versioning.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_output_html_path.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_packaging_metadata.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_packaging_smoke.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_pool.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_preview_script.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_price.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_receipts.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_release_paths.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_runfile_privacy_n1b.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_scoring.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_split_rebindings.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_surface.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_taskmodel_features.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_terminal.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_types_control.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_types_piece_prediction.py +0 -0
- {loopmath-0.2.2 → loopmath-0.2.4}/tests/test_v01_scaffold.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: loopmath
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: Plan agent workflows, record how they went, and learn from your own Claude Code and Codex logs
|
|
5
5
|
Author: QKV Labs
|
|
6
6
|
License-Expression: MIT
|
|
@@ -42,7 +42,7 @@ loopmath helps an orchestrator agent choose how to run a coding task, and learns
|
|
|
42
42
|
|
|
43
43
|
Before a task, it predicts how the user's usual agent workflow will do: the chance of an accepted result, and the cost in tokens and dollars. It shows the other workflows on a success-cost curve and offers two exploration picks. Each pick comes with its gain on every future similar run, its one-time price, and the number of runs it takes to pay back. After the task, the orchestrator records what ran and what came of it. loopmath fills in the token costs from the Claude Code and Codex logs, writes a receipt of predicted against actual, and refits.
|
|
44
44
|
|
|
45
|
-
loopmath never starts or coordinates agents. Claude Code, Codex, herdr or your own tool does that; loopmath is a CLI they call. Everything runs locally.
|
|
45
|
+
loopmath never starts or coordinates agents. Claude Code, Codex, herdr or your own tool does that; loopmath is a CLI they call. Everything runs locally. loopmath connects to no other machine: `loopmath builder` serves its page on 127.0.0.1 only, and no other command opens a network connection. The logs are opened read only, and loopmath writes only to its store (`~/.loopmath`, which holds its caches too), to the skill folders `skill install` names, and to paths you name.
|
|
46
46
|
|
|
47
47
|
The package installs two commands: `loopmath` and its short alias `loop`. If another `loop` is already on your PATH, use `loopmath`.
|
|
48
48
|
|
|
@@ -65,12 +65,13 @@ python3 -m venv .venv
|
|
|
65
65
|
## First run
|
|
66
66
|
|
|
67
67
|
```sh
|
|
68
|
-
loopmath skill install
|
|
68
|
+
loopmath skill install --dry-run # every file it would write, and where; writes nothing
|
|
69
|
+
loopmath skill install # teach your coding agents how to use loopmath
|
|
69
70
|
```
|
|
70
71
|
|
|
71
72
|
Then ask your agent to onboard, for example "onboard loopmath". The agent runs a dry run, asks you one question (which model labels your sessions, with the cost of each option), onboards, fits, and opens the results page.
|
|
72
73
|
|
|
73
|
-
`skill install` writes six skills, one per job
|
|
74
|
+
`skill install` writes six skills, one per job. Each skill's folder also gets its own copy of the shared `reference.md`, with every command and JSON field the skills use, so each skill works on its own. An agent loads only the skill for the job at hand, and each phrase belongs to one skill:
|
|
74
75
|
|
|
75
76
|
| Skill | Ask your agent |
|
|
76
77
|
|---|---|
|
|
@@ -83,7 +84,7 @@ Then ask your agent to onboard, for example "onboard loopmath". The agent runs a
|
|
|
83
84
|
|
|
84
85
|
By default the skills go to every agent whose home exists: Claude Code (`~/.claude/skills/<name>/`, or under `$CLAUDE_CONFIG_DIR`) and Codex (`~/.codex/skills/<name>/`, or under `$CODEX_HOME`). `--target claude-code`, `codex` or `both` picks them yourself. If your Codex has no skills folder, the files go to `~/.codex/loopmath/<name>/` instead, with a short marked block in `~/.codex/AGENTS.md` that lists them. Add `--scope project` to install into the current repository (or `--dir PATH` for another one).
|
|
85
86
|
|
|
86
|
-
It is safe to run again. It records the files it wrote, with their hashes, in `.loopmath-skills.json` beside the skill folders, and it replaces or removes only those. A skill file you changed is kept, with a note. Any other file where a skill goes stops the install before it writes anything, and names the path to move aside. The single skill that 0.1 installed is replaced when it is as 0.1 wrote it. `loopmath skill show NAME` prints one skill, and `loopmath skill uninstall` removes the files it wrote. `loopmath doctor` shows what loopmath can see: logs, agents, store, fit, prices and skills.
|
|
87
|
+
It is safe to run again. It records the files it wrote, with their hashes, in `.loopmath-skills.json` beside the skill folders, and it replaces or removes only those. A skill file you changed is kept, with a note. Any other file where a skill goes stops the install before it writes anything, and names the path to move aside. The single skill that 0.1 installed is replaced when it is as 0.1 wrote it. `loopmath skill show NAME` prints one skill, and `loopmath skill uninstall` removes the files it wrote. `loopmath doctor` shows what loopmath can see: logs, agents, store, fit, prices and skills. To read the logs it builds the log parse cache in the store and keeps it, so the next read is fast, and it says how big the cache is; it changes nothing else in the store.
|
|
87
88
|
|
|
88
89
|
To onboard by hand instead:
|
|
89
90
|
|
|
@@ -92,7 +93,9 @@ loopmath onboard --dry-run # what it found, and
|
|
|
92
93
|
loopmath onboard --labeler claude:claude-haiku-4-5 --yes # record it and run a first fit
|
|
93
94
|
```
|
|
94
95
|
|
|
95
|
-
|
|
96
|
+
The dry run makes no labelling call and writes no runs or fit; like `doctor`, it keeps the log parse cache in the store and says how big it is. The first read of a long history takes several minutes; with the cache, the next one is quick.
|
|
97
|
+
|
|
98
|
+
`onboard` reads your recent Claude Code and Codex sessions (the last 90 days unless you pass `--since`). It groups them into runs, labels each group's task type with a model you choose, names your usual workflow per task type and repository (sessions outside a git repository go under `(no repo)`), and fits. loopmath never picks the labelling model for you. `--labeler` takes one of:
|
|
96
99
|
|
|
97
100
|
- `claude:<model>`, through your `claude` CLI;
|
|
98
101
|
- `codex:<model>`, through your `codex` CLI;
|
|
@@ -103,6 +106,8 @@ Reading the history uses up to 8 worker processes (one per CPU, at most 8). Set
|
|
|
103
106
|
|
|
104
107
|
loopmath ships with a prior built from our own sweeps and experiments, so `recommend` gives an answer before you have any history. Your own runs then move it.
|
|
105
108
|
|
|
109
|
+
The prior ships inside the package: our runs, in the shared form (no titles, paths, commands or free text), and the published benchmark results. They are the same files we fit with, and each release updates them. `onboard` and the results page say in one line which prior they start from, and `loopmath prior show` lists it source by source.
|
|
110
|
+
|
|
106
111
|
## The loop
|
|
107
112
|
|
|
108
113
|
The plan and record skills take an agent through the loop in three commands:
|
|
@@ -113,6 +118,8 @@ loopmath run start --rec REC --choice goal --base-commit SHA --json # the h
|
|
|
113
118
|
loopmath run record --run RUN --session UUID --verified tests=pass --json # costs from the logs, the outcome, the receipt
|
|
114
119
|
```
|
|
115
120
|
|
|
121
|
+
With `--run`, a session that started before the run counts from the run's start (a Codex session counts whole). Give `--since TS` and `--until TS` when the task's work began or ended at another time; `--since` before `run start` moves the run's start back. When no commit is found after the base commit, the record says where it looked; pass `--commit SHA`. `loopmath run sessions` lists the recent Claude Code and Codex sessions in this folder with their ids, for `--session ID`. Outside a Claude Code tool shell, `--session self` uses the one Claude Code session in this folder active in the last 10 minutes.
|
|
122
|
+
|
|
116
123
|
The same loop step by step, for a tool of your own:
|
|
117
124
|
|
|
118
125
|
```sh
|
|
@@ -140,37 +147,41 @@ loopmath run finish --run RUN
|
|
|
140
147
|
loopmath outcome --commit SHA --signal incident=INC-42 --kind event --source tracker
|
|
141
148
|
```
|
|
142
149
|
|
|
143
|
-
|
|
150
|
+
The usual workflow is the one most of your habit runs used: the runs onboard brought in, and runs started with `--source habit`. Runs of a recommended alternative or an exploration pick are recorded but never make a workflow your usual; `recommend --usual CFG` names one. Under the reference, `recommend` says where it comes from; each alternative shows its own chance and costs and what it changes from the pick, and an exploration pick says after how many similar runs it pays back. When the text would run past 25 lines it lists fewer alternatives and says how many more `recommend --json` has.
|
|
151
|
+
|
|
152
|
+
A pair runs the goal workflow and an exploration pick from the same base commit, in separate worktrees. `loopmath run start --rec REC --choice pair` starts both, on a new slate. To start them one at a time, save the recommendation (`recommend ... --json > rec.json`) and start each run from it, so they share one task: `loopmath run start --task-file rec.json --config CFG --source alternative --new-slate` for the goal, then the same with the pick's configuration, `--source exploration` and `--slate SLT`. A blinded referee then picks the better change, which you record with `loopmath outcome --slate SLT --prefer RUN --judge referee --blinded`. `loopmath runs --slate SLT` says which run the referee preferred.
|
|
144
153
|
|
|
145
|
-
A run counts as a success when it is accepted under your rule. By default that means the task's tests pass. A rule can also be a score target: `loopmath recommend ... --target 'heldout_perf>=2400'` or `--target 'runtime_s<=200'` gives the expected score and the chance of reaching the target. Set standing rules and other options with `loopmath config set KEY VALUE
|
|
154
|
+
A run counts as a success when it is accepted under your rule. By default that means the task's tests pass. A rule can also be a score target: `loopmath recommend ... --target 'heldout_perf>=2400'` or `--target 'runtime_s<=200'` gives the expected score and the chance of reaching the target. Set standing rules and other options with `loopmath config set KEY VALUE` (`loopmath config get` lists every key, set or not, and `config set` refuses a key loopmath does not read), and the spending cap with `loopmath budget --usd X --period month`. Spend counts your runs and onboard's labelling calls; runs onboard brought in from your logs are shown apart and not counted. A run you record with `--source habit` counts.
|
|
146
155
|
|
|
147
|
-
Runs recorded by another tool that writes OCP v0.3, such as an experiment runner, come in with `loopmath run import DIR --finish`: several files or a directory, with one refit at the end (`--no-fit` skips it). Runs in your store always count as yours, whatever source their documents name. `loopmath fit --without SOURCE` leaves out one shipped prior source, and `loopmath status` names the options of the current fit.
|
|
156
|
+
Runs recorded by another tool that writes OCP v0.3, such as an experiment runner, come in with `loopmath run import DIR --finish`: several files or a directory, with one refit at the end (`--no-fit` skips it). It says how many runs were new and how many were already in the store; importing finished runs into a store with no fit starts a fit. Runs in your store always count as yours, whatever source their documents name. `loopmath fit --without SOURCE` leaves out one shipped prior source, and `loopmath status` names the options of the current fit.
|
|
148
157
|
|
|
149
158
|
## The three views
|
|
150
159
|
|
|
151
|
-
Each view is a self-contained HTML file written by a command;
|
|
160
|
+
Each view is a self-contained HTML file written by a command; opening one needs no server. The same numbers are available with `--json`.
|
|
152
161
|
|
|
153
162
|
- **Previous runs:** `loopmath runs --html`. Every recorded run with its workflow graph, costs, signals and receipt.
|
|
154
163
|
- **Plans for a task:** `loopmath recommend ... --html`. The candidates on a success-cost chart. Click one to see its workflow graph with per-piece predictions.
|
|
155
|
-
- **Current estimates:** `loopmath posterior --html`. What loopmath believes at each level (model, effort, role, topology, task type, repository, feature), each with a range. Add `--workflow CFG` (a configuration id from `loopmath recommend` or your runs) to see the estimate for each piece of one workflow.
|
|
164
|
+
- **Current estimates:** `loopmath posterior --html`. What loopmath believes at each level (model, effort, role, topology, task type, repository, feature), each with a range. Add `--workflow CFG` (a configuration id from `loopmath recommend` or your runs) to see the estimate for each piece of one workflow, on the task its runs were for, or, if it never ran, the task it was recommended for; `--type` and `--repo` pick another.
|
|
156
165
|
|
|
157
166
|
Without a path, `--html` writes the page under `~/.loopmath/views/` and prints where it went.
|
|
158
167
|
|
|
168
|
+
The workflow builder is the one page that is served: `loopmath builder --type bug_fix --repo acme/api` serves it on 127.0.0.1 and opens it in your browser (`--no-open` prints the address instead); Ctrl+C stops it. Pick a shape, change models, efforts, widths and pieces, and see the estimated numbers for the task, the same ones `recommend` gives.
|
|
169
|
+
|
|
159
170
|
## Commands
|
|
160
171
|
|
|
161
172
|
| Group | Commands |
|
|
162
173
|
|---|---|
|
|
163
|
-
| Plan | `task-types`, `workflows` (list, show, validate, diff), `recommend` |
|
|
164
|
-
| Record | `run` (start, attempt, artifact, finish,
|
|
174
|
+
| Plan | `task-types`, `workflows` (list, show, validate, diff), `recommend`, `builder` |
|
|
175
|
+
| Record | `run` (start, record, import, attempt, artifact, finish, sessions), `outcome`, `budget`, `config` (get, set) |
|
|
165
176
|
| Learn | `fit`, `onboard`, `share`, `prior` |
|
|
166
|
-
| View | `runs`, `posterior`, `status`, `report`, `doctor` |
|
|
177
|
+
| View | `runs`, `posterior`, `status`, `report`, `doctor`, `verify-receipts` |
|
|
167
178
|
| Skill | `skill` (install, uninstall, show) |
|
|
168
179
|
| OCP | `ocp` (validate, migrate) |
|
|
169
|
-
| Log analysis | `analyze`, `graph`, `adapt`, `prices`, `validate-prices`, `scan
|
|
180
|
+
| Log analysis | `analyze`, `graph`, `adapt`, `prices`, `validate-prices`, `scan` |
|
|
170
181
|
|
|
171
|
-
Each command prints a short summary by default. With `--json`, it prints exactly one JSON object instead. Exit codes: 0 ok, 1 user error, 2 not found, 3 not implemented, 4 store locked, 5 no fit yet. For flags, `loopmath <command> --help` is the source of truth.
|
|
182
|
+
Each command prints a short summary by default. With `--json`, it prints exactly one JSON object instead. Exit codes: 0 ok, 1 user error, 2 not found, 3 not implemented, 4 store locked, 5 no fit yet. For flags, `loopmath <command> --help` is the source of truth. Commands, pages and the `runs` table show times in your local time with the zone; the store and `--json` keep UTC. A cost under a cent shows one significant digit (`$0.004`), and an exact zero is `$0`.
|
|
172
183
|
|
|
173
|
-
A workflow is a TOML file. `loopmath workflows list` shows the catalog and yours, which live in `~/.loopmath/workflows/`. This one implements, then sends a rejected change back once or twice:
|
|
184
|
+
A workflow is a TOML file. `loopmath workflows list` shows the catalog and yours, which live in `~/.loopmath/workflows/`. It also lists the shapes loopmath composes from catalog pieces, such as `team`; `loopmath workflows show team` says what one is and that `recommend` does not offer it. This one implements, then sends a rejected change back once or twice:
|
|
174
185
|
|
|
175
186
|
```toml
|
|
176
187
|
id = "implement_review_mine"
|
|
@@ -220,7 +231,7 @@ model = "gpt-5.6-sol"
|
|
|
220
231
|
effort = "high"
|
|
221
232
|
```
|
|
222
233
|
|
|
223
|
-
Check it with `loopmath workflows validate FILE`, compare it with `loopmath workflows diff implement_review FILE`, and pass it to `recommend --workflow FILE` to have it considered, or to `run start --workflow FILE` to record a run with its settings (`--set PIECE=HARNESS:MODEL:EFFORT` overrides a piece).
|
|
234
|
+
Check it with `loopmath workflows validate FILE`, compare it with `loopmath workflows diff implement_review FILE`, and pass it to `recommend --workflow FILE` to have it considered, or to `run start --workflow FILE --source user_edit` to record a run with its settings (`--set PIECE=HARNESS:MODEL:EFFORT` overrides a piece).
|
|
224
235
|
|
|
225
236
|
## The store and privacy
|
|
226
237
|
|
|
@@ -230,13 +241,15 @@ The store is `~/.loopmath`. Set `LOOPMATH_HOME` or pass `--home` to put it elsew
|
|
|
230
241
|
- signals, receipts and fits;
|
|
231
242
|
- your config and your workflows;
|
|
232
243
|
- the views you write;
|
|
233
|
-
- the log parse cache.
|
|
244
|
+
- the caches: the log parse cache, and the folder where `fit --full` compiles its model (when that compile fails, it also leaves the C code it tried in the system temp folder and prints where).
|
|
234
245
|
|
|
235
|
-
Do not edit the store by hand; use the commands.
|
|
246
|
+
Do not edit the store by hand; use the commands. `loopmath verify-receipts` checks the receipts in your store; give a file to verify a research receipt ledger instead.
|
|
236
247
|
|
|
237
248
|
Run files use the `metadata_only` privacy profile. They keep structure, models, tokens, dollars, paths and verdicts, but not transcript text.
|
|
238
249
|
|
|
239
|
-
`loopmath share --out FILE` writes a reduced copy you can send to us. It keeps task types, workflows, models, tokens, dollars and outcomes. Repository names are hashed. Titles, paths, commands, session ids and commit shas are removed. `loopmath share --preview` prints exactly what would leave.
|
|
250
|
+
`loopmath share --out FILE` writes a reduced copy you can send to us. It keeps task types, workflows, models, tokens, dollars and outcomes. Repository names are hashed. Titles, paths, commands, session ids and commit shas are removed. `loopmath share --preview` prints exactly what would leave. `--out FILE.json` writes plain JSON you can read; any other name, such as `share.json.gz`, writes gzip.
|
|
251
|
+
|
|
252
|
+
`loopmath prior import-shared FILE` adds a file another organization shared with you to your priors (either format; not one this store shared itself), and `loopmath prior remove-shared ORG` takes it out again; run `loopmath fit` after either.
|
|
240
253
|
|
|
241
254
|
## Analyzing logs without recording
|
|
242
255
|
|
|
@@ -247,13 +260,15 @@ loopmath analyze # cost per accepted run from the last 14 days o
|
|
|
247
260
|
loopmath graph --workspace NAME --format html --out graph.html
|
|
248
261
|
```
|
|
249
262
|
|
|
250
|
-
`analyze` reads `~/.claude/projects` and `~/.codex/sessions`. It grades the outcome evidence it finds, prices known models, and prints cost per accepted run with an 80% band. It also lists what it could not use and why.
|
|
263
|
+
`analyze` reads `~/.claude/projects` and `~/.codex/sessions`. It grades the outcome evidence it finds, prices known models, and prints cost per accepted run with an 80% band. It also lists what it could not use and why; when no workflow configuration has enough runs to compare, it says how many runs it read and what kept each out, and what to try (`--min-n`, `--grading`). `loopmath analyze --json` prints the same as one JSON object, and `--home PATH` keeps its parse cache in that store.
|
|
264
|
+
|
|
265
|
+
`loopmath prices` lists the packaged prices with the source of each. A rate marked "rate not confirmed" is a best public-price guess, and every dollar figure priced with one says so.
|
|
251
266
|
|
|
252
|
-
`graph` rebuilds which agent launched which, and which session read what another wrote. Its formats are `ocp`, `json`, `dot`, `run` and `html`. See the [workflow graph guide](docs/graph.md) and [adapters](docs/adapters.md).
|
|
267
|
+
`graph` rebuilds which agent launched which, and which session read what another wrote. Its formats are `ocp`, `json`, `dot`, `run` and `html`. `graph --out FILE` and `adapt NAME --out FILE` write to any path you name: missing folders are created, an existing file is replaced, and a directory is refused. `graph` prints a short summary on stderr; `--verbose` adds every count of what was skipped or could not be placed. See the [workflow graph guide](docs/graph.md) and [adapters](docs/adapters.md).
|
|
253
268
|
|
|
254
269
|
## Research data
|
|
255
270
|
|
|
256
|
-
`loopmath research
|
|
271
|
+
`loopmath research --help` lists the verbs that read research data folders, which are not part of the package: `research fit` and `research transfer-test` read sweep run records, and `research analyze-e0` reads a session corpus. Name the folders with a flag (`--sweep-dir`, `--corpus`), an environment variable (`LOOPMATH_SWEEP_DIR`, `LOOPMATH_E0_CORPUS`), or config (`loopmath config set research.sweep_dir PATH`, `research.e0_corpus`). `research fit` and `research transfer-test` need the `bayes` extra (`pip install 'loopmath[bayes]'`), and `research analyze-e0` the `e0` extra. `loopmath prior build --out DIR` rebuilds the packaged prior bundle from research data folders like these; `loopmath prior build --help` names them.
|
|
257
272
|
|
|
258
273
|
## More
|
|
259
274
|
|
|
@@ -4,7 +4,7 @@ loopmath helps an orchestrator agent choose how to run a coding task, and learns
|
|
|
4
4
|
|
|
5
5
|
Before a task, it predicts how the user's usual agent workflow will do: the chance of an accepted result, and the cost in tokens and dollars. It shows the other workflows on a success-cost curve and offers two exploration picks. Each pick comes with its gain on every future similar run, its one-time price, and the number of runs it takes to pay back. After the task, the orchestrator records what ran and what came of it. loopmath fills in the token costs from the Claude Code and Codex logs, writes a receipt of predicted against actual, and refits.
|
|
6
6
|
|
|
7
|
-
loopmath never starts or coordinates agents. Claude Code, Codex, herdr or your own tool does that; loopmath is a CLI they call. Everything runs locally.
|
|
7
|
+
loopmath never starts or coordinates agents. Claude Code, Codex, herdr or your own tool does that; loopmath is a CLI they call. Everything runs locally. loopmath connects to no other machine: `loopmath builder` serves its page on 127.0.0.1 only, and no other command opens a network connection. The logs are opened read only, and loopmath writes only to its store (`~/.loopmath`, which holds its caches too), to the skill folders `skill install` names, and to paths you name.
|
|
8
8
|
|
|
9
9
|
The package installs two commands: `loopmath` and its short alias `loop`. If another `loop` is already on your PATH, use `loopmath`.
|
|
10
10
|
|
|
@@ -27,12 +27,13 @@ python3 -m venv .venv
|
|
|
27
27
|
## First run
|
|
28
28
|
|
|
29
29
|
```sh
|
|
30
|
-
loopmath skill install
|
|
30
|
+
loopmath skill install --dry-run # every file it would write, and where; writes nothing
|
|
31
|
+
loopmath skill install # teach your coding agents how to use loopmath
|
|
31
32
|
```
|
|
32
33
|
|
|
33
34
|
Then ask your agent to onboard, for example "onboard loopmath". The agent runs a dry run, asks you one question (which model labels your sessions, with the cost of each option), onboards, fits, and opens the results page.
|
|
34
35
|
|
|
35
|
-
`skill install` writes six skills, one per job
|
|
36
|
+
`skill install` writes six skills, one per job. Each skill's folder also gets its own copy of the shared `reference.md`, with every command and JSON field the skills use, so each skill works on its own. An agent loads only the skill for the job at hand, and each phrase belongs to one skill:
|
|
36
37
|
|
|
37
38
|
| Skill | Ask your agent |
|
|
38
39
|
|---|---|
|
|
@@ -45,7 +46,7 @@ Then ask your agent to onboard, for example "onboard loopmath". The agent runs a
|
|
|
45
46
|
|
|
46
47
|
By default the skills go to every agent whose home exists: Claude Code (`~/.claude/skills/<name>/`, or under `$CLAUDE_CONFIG_DIR`) and Codex (`~/.codex/skills/<name>/`, or under `$CODEX_HOME`). `--target claude-code`, `codex` or `both` picks them yourself. If your Codex has no skills folder, the files go to `~/.codex/loopmath/<name>/` instead, with a short marked block in `~/.codex/AGENTS.md` that lists them. Add `--scope project` to install into the current repository (or `--dir PATH` for another one).
|
|
47
48
|
|
|
48
|
-
It is safe to run again. It records the files it wrote, with their hashes, in `.loopmath-skills.json` beside the skill folders, and it replaces or removes only those. A skill file you changed is kept, with a note. Any other file where a skill goes stops the install before it writes anything, and names the path to move aside. The single skill that 0.1 installed is replaced when it is as 0.1 wrote it. `loopmath skill show NAME` prints one skill, and `loopmath skill uninstall` removes the files it wrote. `loopmath doctor` shows what loopmath can see: logs, agents, store, fit, prices and skills.
|
|
49
|
+
It is safe to run again. It records the files it wrote, with their hashes, in `.loopmath-skills.json` beside the skill folders, and it replaces or removes only those. A skill file you changed is kept, with a note. Any other file where a skill goes stops the install before it writes anything, and names the path to move aside. The single skill that 0.1 installed is replaced when it is as 0.1 wrote it. `loopmath skill show NAME` prints one skill, and `loopmath skill uninstall` removes the files it wrote. `loopmath doctor` shows what loopmath can see: logs, agents, store, fit, prices and skills. To read the logs it builds the log parse cache in the store and keeps it, so the next read is fast, and it says how big the cache is; it changes nothing else in the store.
|
|
49
50
|
|
|
50
51
|
To onboard by hand instead:
|
|
51
52
|
|
|
@@ -54,7 +55,9 @@ loopmath onboard --dry-run # what it found, and
|
|
|
54
55
|
loopmath onboard --labeler claude:claude-haiku-4-5 --yes # record it and run a first fit
|
|
55
56
|
```
|
|
56
57
|
|
|
57
|
-
|
|
58
|
+
The dry run makes no labelling call and writes no runs or fit; like `doctor`, it keeps the log parse cache in the store and says how big it is. The first read of a long history takes several minutes; with the cache, the next one is quick.
|
|
59
|
+
|
|
60
|
+
`onboard` reads your recent Claude Code and Codex sessions (the last 90 days unless you pass `--since`). It groups them into runs, labels each group's task type with a model you choose, names your usual workflow per task type and repository (sessions outside a git repository go under `(no repo)`), and fits. loopmath never picks the labelling model for you. `--labeler` takes one of:
|
|
58
61
|
|
|
59
62
|
- `claude:<model>`, through your `claude` CLI;
|
|
60
63
|
- `codex:<model>`, through your `codex` CLI;
|
|
@@ -65,6 +68,8 @@ Reading the history uses up to 8 worker processes (one per CPU, at most 8). Set
|
|
|
65
68
|
|
|
66
69
|
loopmath ships with a prior built from our own sweeps and experiments, so `recommend` gives an answer before you have any history. Your own runs then move it.
|
|
67
70
|
|
|
71
|
+
The prior ships inside the package: our runs, in the shared form (no titles, paths, commands or free text), and the published benchmark results. They are the same files we fit with, and each release updates them. `onboard` and the results page say in one line which prior they start from, and `loopmath prior show` lists it source by source.
|
|
72
|
+
|
|
68
73
|
## The loop
|
|
69
74
|
|
|
70
75
|
The plan and record skills take an agent through the loop in three commands:
|
|
@@ -75,6 +80,8 @@ loopmath run start --rec REC --choice goal --base-commit SHA --json # the h
|
|
|
75
80
|
loopmath run record --run RUN --session UUID --verified tests=pass --json # costs from the logs, the outcome, the receipt
|
|
76
81
|
```
|
|
77
82
|
|
|
83
|
+
With `--run`, a session that started before the run counts from the run's start (a Codex session counts whole). Give `--since TS` and `--until TS` when the task's work began or ended at another time; `--since` before `run start` moves the run's start back. When no commit is found after the base commit, the record says where it looked; pass `--commit SHA`. `loopmath run sessions` lists the recent Claude Code and Codex sessions in this folder with their ids, for `--session ID`. Outside a Claude Code tool shell, `--session self` uses the one Claude Code session in this folder active in the last 10 minutes.
|
|
84
|
+
|
|
78
85
|
The same loop step by step, for a tool of your own:
|
|
79
86
|
|
|
80
87
|
```sh
|
|
@@ -102,37 +109,41 @@ loopmath run finish --run RUN
|
|
|
102
109
|
loopmath outcome --commit SHA --signal incident=INC-42 --kind event --source tracker
|
|
103
110
|
```
|
|
104
111
|
|
|
105
|
-
|
|
112
|
+
The usual workflow is the one most of your habit runs used: the runs onboard brought in, and runs started with `--source habit`. Runs of a recommended alternative or an exploration pick are recorded but never make a workflow your usual; `recommend --usual CFG` names one. Under the reference, `recommend` says where it comes from; each alternative shows its own chance and costs and what it changes from the pick, and an exploration pick says after how many similar runs it pays back. When the text would run past 25 lines it lists fewer alternatives and says how many more `recommend --json` has.
|
|
113
|
+
|
|
114
|
+
A pair runs the goal workflow and an exploration pick from the same base commit, in separate worktrees. `loopmath run start --rec REC --choice pair` starts both, on a new slate. To start them one at a time, save the recommendation (`recommend ... --json > rec.json`) and start each run from it, so they share one task: `loopmath run start --task-file rec.json --config CFG --source alternative --new-slate` for the goal, then the same with the pick's configuration, `--source exploration` and `--slate SLT`. A blinded referee then picks the better change, which you record with `loopmath outcome --slate SLT --prefer RUN --judge referee --blinded`. `loopmath runs --slate SLT` says which run the referee preferred.
|
|
106
115
|
|
|
107
|
-
A run counts as a success when it is accepted under your rule. By default that means the task's tests pass. A rule can also be a score target: `loopmath recommend ... --target 'heldout_perf>=2400'` or `--target 'runtime_s<=200'` gives the expected score and the chance of reaching the target. Set standing rules and other options with `loopmath config set KEY VALUE
|
|
116
|
+
A run counts as a success when it is accepted under your rule. By default that means the task's tests pass. A rule can also be a score target: `loopmath recommend ... --target 'heldout_perf>=2400'` or `--target 'runtime_s<=200'` gives the expected score and the chance of reaching the target. Set standing rules and other options with `loopmath config set KEY VALUE` (`loopmath config get` lists every key, set or not, and `config set` refuses a key loopmath does not read), and the spending cap with `loopmath budget --usd X --period month`. Spend counts your runs and onboard's labelling calls; runs onboard brought in from your logs are shown apart and not counted. A run you record with `--source habit` counts.
|
|
108
117
|
|
|
109
|
-
Runs recorded by another tool that writes OCP v0.3, such as an experiment runner, come in with `loopmath run import DIR --finish`: several files or a directory, with one refit at the end (`--no-fit` skips it). Runs in your store always count as yours, whatever source their documents name. `loopmath fit --without SOURCE` leaves out one shipped prior source, and `loopmath status` names the options of the current fit.
|
|
118
|
+
Runs recorded by another tool that writes OCP v0.3, such as an experiment runner, come in with `loopmath run import DIR --finish`: several files or a directory, with one refit at the end (`--no-fit` skips it). It says how many runs were new and how many were already in the store; importing finished runs into a store with no fit starts a fit. Runs in your store always count as yours, whatever source their documents name. `loopmath fit --without SOURCE` leaves out one shipped prior source, and `loopmath status` names the options of the current fit.
|
|
110
119
|
|
|
111
120
|
## The three views
|
|
112
121
|
|
|
113
|
-
Each view is a self-contained HTML file written by a command;
|
|
122
|
+
Each view is a self-contained HTML file written by a command; opening one needs no server. The same numbers are available with `--json`.
|
|
114
123
|
|
|
115
124
|
- **Previous runs:** `loopmath runs --html`. Every recorded run with its workflow graph, costs, signals and receipt.
|
|
116
125
|
- **Plans for a task:** `loopmath recommend ... --html`. The candidates on a success-cost chart. Click one to see its workflow graph with per-piece predictions.
|
|
117
|
-
- **Current estimates:** `loopmath posterior --html`. What loopmath believes at each level (model, effort, role, topology, task type, repository, feature), each with a range. Add `--workflow CFG` (a configuration id from `loopmath recommend` or your runs) to see the estimate for each piece of one workflow.
|
|
126
|
+
- **Current estimates:** `loopmath posterior --html`. What loopmath believes at each level (model, effort, role, topology, task type, repository, feature), each with a range. Add `--workflow CFG` (a configuration id from `loopmath recommend` or your runs) to see the estimate for each piece of one workflow, on the task its runs were for, or, if it never ran, the task it was recommended for; `--type` and `--repo` pick another.
|
|
118
127
|
|
|
119
128
|
Without a path, `--html` writes the page under `~/.loopmath/views/` and prints where it went.
|
|
120
129
|
|
|
130
|
+
The workflow builder is the one page that is served: `loopmath builder --type bug_fix --repo acme/api` serves it on 127.0.0.1 and opens it in your browser (`--no-open` prints the address instead); Ctrl+C stops it. Pick a shape, change models, efforts, widths and pieces, and see the estimated numbers for the task, the same ones `recommend` gives.
|
|
131
|
+
|
|
121
132
|
## Commands
|
|
122
133
|
|
|
123
134
|
| Group | Commands |
|
|
124
135
|
|---|---|
|
|
125
|
-
| Plan | `task-types`, `workflows` (list, show, validate, diff), `recommend` |
|
|
126
|
-
| Record | `run` (start, attempt, artifact, finish,
|
|
136
|
+
| Plan | `task-types`, `workflows` (list, show, validate, diff), `recommend`, `builder` |
|
|
137
|
+
| Record | `run` (start, record, import, attempt, artifact, finish, sessions), `outcome`, `budget`, `config` (get, set) |
|
|
127
138
|
| Learn | `fit`, `onboard`, `share`, `prior` |
|
|
128
|
-
| View | `runs`, `posterior`, `status`, `report`, `doctor` |
|
|
139
|
+
| View | `runs`, `posterior`, `status`, `report`, `doctor`, `verify-receipts` |
|
|
129
140
|
| Skill | `skill` (install, uninstall, show) |
|
|
130
141
|
| OCP | `ocp` (validate, migrate) |
|
|
131
|
-
| Log analysis | `analyze`, `graph`, `adapt`, `prices`, `validate-prices`, `scan
|
|
142
|
+
| Log analysis | `analyze`, `graph`, `adapt`, `prices`, `validate-prices`, `scan` |
|
|
132
143
|
|
|
133
|
-
Each command prints a short summary by default. With `--json`, it prints exactly one JSON object instead. Exit codes: 0 ok, 1 user error, 2 not found, 3 not implemented, 4 store locked, 5 no fit yet. For flags, `loopmath <command> --help` is the source of truth.
|
|
144
|
+
Each command prints a short summary by default. With `--json`, it prints exactly one JSON object instead. Exit codes: 0 ok, 1 user error, 2 not found, 3 not implemented, 4 store locked, 5 no fit yet. For flags, `loopmath <command> --help` is the source of truth. Commands, pages and the `runs` table show times in your local time with the zone; the store and `--json` keep UTC. A cost under a cent shows one significant digit (`$0.004`), and an exact zero is `$0`.
|
|
134
145
|
|
|
135
|
-
A workflow is a TOML file. `loopmath workflows list` shows the catalog and yours, which live in `~/.loopmath/workflows/`. This one implements, then sends a rejected change back once or twice:
|
|
146
|
+
A workflow is a TOML file. `loopmath workflows list` shows the catalog and yours, which live in `~/.loopmath/workflows/`. It also lists the shapes loopmath composes from catalog pieces, such as `team`; `loopmath workflows show team` says what one is and that `recommend` does not offer it. This one implements, then sends a rejected change back once or twice:
|
|
136
147
|
|
|
137
148
|
```toml
|
|
138
149
|
id = "implement_review_mine"
|
|
@@ -182,7 +193,7 @@ model = "gpt-5.6-sol"
|
|
|
182
193
|
effort = "high"
|
|
183
194
|
```
|
|
184
195
|
|
|
185
|
-
Check it with `loopmath workflows validate FILE`, compare it with `loopmath workflows diff implement_review FILE`, and pass it to `recommend --workflow FILE` to have it considered, or to `run start --workflow FILE` to record a run with its settings (`--set PIECE=HARNESS:MODEL:EFFORT` overrides a piece).
|
|
196
|
+
Check it with `loopmath workflows validate FILE`, compare it with `loopmath workflows diff implement_review FILE`, and pass it to `recommend --workflow FILE` to have it considered, or to `run start --workflow FILE --source user_edit` to record a run with its settings (`--set PIECE=HARNESS:MODEL:EFFORT` overrides a piece).
|
|
186
197
|
|
|
187
198
|
## The store and privacy
|
|
188
199
|
|
|
@@ -192,13 +203,15 @@ The store is `~/.loopmath`. Set `LOOPMATH_HOME` or pass `--home` to put it elsew
|
|
|
192
203
|
- signals, receipts and fits;
|
|
193
204
|
- your config and your workflows;
|
|
194
205
|
- the views you write;
|
|
195
|
-
- the log parse cache.
|
|
206
|
+
- the caches: the log parse cache, and the folder where `fit --full` compiles its model (when that compile fails, it also leaves the C code it tried in the system temp folder and prints where).
|
|
196
207
|
|
|
197
|
-
Do not edit the store by hand; use the commands.
|
|
208
|
+
Do not edit the store by hand; use the commands. `loopmath verify-receipts` checks the receipts in your store; give a file to verify a research receipt ledger instead.
|
|
198
209
|
|
|
199
210
|
Run files use the `metadata_only` privacy profile. They keep structure, models, tokens, dollars, paths and verdicts, but not transcript text.
|
|
200
211
|
|
|
201
|
-
`loopmath share --out FILE` writes a reduced copy you can send to us. It keeps task types, workflows, models, tokens, dollars and outcomes. Repository names are hashed. Titles, paths, commands, session ids and commit shas are removed. `loopmath share --preview` prints exactly what would leave.
|
|
212
|
+
`loopmath share --out FILE` writes a reduced copy you can send to us. It keeps task types, workflows, models, tokens, dollars and outcomes. Repository names are hashed. Titles, paths, commands, session ids and commit shas are removed. `loopmath share --preview` prints exactly what would leave. `--out FILE.json` writes plain JSON you can read; any other name, such as `share.json.gz`, writes gzip.
|
|
213
|
+
|
|
214
|
+
`loopmath prior import-shared FILE` adds a file another organization shared with you to your priors (either format; not one this store shared itself), and `loopmath prior remove-shared ORG` takes it out again; run `loopmath fit` after either.
|
|
202
215
|
|
|
203
216
|
## Analyzing logs without recording
|
|
204
217
|
|
|
@@ -209,13 +222,15 @@ loopmath analyze # cost per accepted run from the last 14 days o
|
|
|
209
222
|
loopmath graph --workspace NAME --format html --out graph.html
|
|
210
223
|
```
|
|
211
224
|
|
|
212
|
-
`analyze` reads `~/.claude/projects` and `~/.codex/sessions`. It grades the outcome evidence it finds, prices known models, and prints cost per accepted run with an 80% band. It also lists what it could not use and why.
|
|
225
|
+
`analyze` reads `~/.claude/projects` and `~/.codex/sessions`. It grades the outcome evidence it finds, prices known models, and prints cost per accepted run with an 80% band. It also lists what it could not use and why; when no workflow configuration has enough runs to compare, it says how many runs it read and what kept each out, and what to try (`--min-n`, `--grading`). `loopmath analyze --json` prints the same as one JSON object, and `--home PATH` keeps its parse cache in that store.
|
|
226
|
+
|
|
227
|
+
`loopmath prices` lists the packaged prices with the source of each. A rate marked "rate not confirmed" is a best public-price guess, and every dollar figure priced with one says so.
|
|
213
228
|
|
|
214
|
-
`graph` rebuilds which agent launched which, and which session read what another wrote. Its formats are `ocp`, `json`, `dot`, `run` and `html`. See the [workflow graph guide](docs/graph.md) and [adapters](docs/adapters.md).
|
|
229
|
+
`graph` rebuilds which agent launched which, and which session read what another wrote. Its formats are `ocp`, `json`, `dot`, `run` and `html`. `graph --out FILE` and `adapt NAME --out FILE` write to any path you name: missing folders are created, an existing file is replaced, and a directory is refused. `graph` prints a short summary on stderr; `--verbose` adds every count of what was skipped or could not be placed. See the [workflow graph guide](docs/graph.md) and [adapters](docs/adapters.md).
|
|
215
230
|
|
|
216
231
|
## Research data
|
|
217
232
|
|
|
218
|
-
`loopmath research
|
|
233
|
+
`loopmath research --help` lists the verbs that read research data folders, which are not part of the package: `research fit` and `research transfer-test` read sweep run records, and `research analyze-e0` reads a session corpus. Name the folders with a flag (`--sweep-dir`, `--corpus`), an environment variable (`LOOPMATH_SWEEP_DIR`, `LOOPMATH_E0_CORPUS`), or config (`loopmath config set research.sweep_dir PATH`, `research.e0_corpus`). `research fit` and `research transfer-test` need the `bayes` extra (`pip install 'loopmath[bayes]'`), and `research analyze-e0` the `e0` extra. `loopmath prior build --out DIR` rebuilds the packaged prior bundle from research data folders like these; `loopmath prior build --help` names them.
|
|
219
234
|
|
|
220
235
|
## More
|
|
221
236
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "loopmath"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.4"
|
|
8
8
|
description = "Plan agent workflows, record how they went, and learn from your own Claude Code and Codex logs"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -470,7 +470,7 @@ class AtriumAdapter(Adapter):
|
|
|
470
470
|
return {
|
|
471
471
|
"ocp": "0.2",
|
|
472
472
|
"producer": {
|
|
473
|
-
"name": "
|
|
473
|
+
"name": "loopmath/adapter-atrium",
|
|
474
474
|
"framework": "atrium",
|
|
475
475
|
"source_contract": "atrium/timeline+task-run-segments",
|
|
476
476
|
"capabilities": {
|
|
@@ -408,7 +408,7 @@ class BbAdapter(Adapter):
|
|
|
408
408
|
)
|
|
409
409
|
ignored_snapshots = sum(thread["ignored_token_snapshots"] for thread in selected)
|
|
410
410
|
producer: dict[str, Any] = {
|
|
411
|
-
"name": "
|
|
411
|
+
"name": "loopmath/adapter-bb",
|
|
412
412
|
"framework": "bb",
|
|
413
413
|
"source_contract": "bb/sqlite",
|
|
414
414
|
"capabilities": {
|
|
@@ -386,7 +386,7 @@ def _emit_document(
|
|
|
386
386
|
else:
|
|
387
387
|
source_contract = "opencode export"
|
|
388
388
|
producer: dict[str, Any] = {
|
|
389
|
-
"name": "
|
|
389
|
+
"name": "loopmath/adapter-opencode",
|
|
390
390
|
"framework": "opencode",
|
|
391
391
|
"source_contract": source_contract,
|
|
392
392
|
"capabilities": {
|
|
@@ -383,7 +383,7 @@ class OtelGenAIAdapter(Adapter):
|
|
|
383
383
|
return {
|
|
384
384
|
"ocp": "0.2",
|
|
385
385
|
"producer": {
|
|
386
|
-
"name": "
|
|
386
|
+
"name": "loopmath/adapter-otel-genai",
|
|
387
387
|
"framework": "+".join(harnesses) if harnesses else "unknown",
|
|
388
388
|
"source_contract": "OTLP/JSON file exporter",
|
|
389
389
|
"capabilities": {
|
|
@@ -21,9 +21,13 @@ from __future__ import annotations
|
|
|
21
21
|
import time
|
|
22
22
|
|
|
23
23
|
import numpy as np
|
|
24
|
-
|
|
25
|
-
import
|
|
26
|
-
|
|
24
|
+
|
|
25
|
+
from ..fit_bayes import use_store_compiledir
|
|
26
|
+
|
|
27
|
+
use_store_compiledir() # before pytensor is imported: its compile folder goes in the store's cache
|
|
28
|
+
import pymc as pm # noqa: E402
|
|
29
|
+
import pytensor # noqa: E402
|
|
30
|
+
import pytensor.tensor as pt # noqa: E402
|
|
27
31
|
|
|
28
32
|
from .gaussian import HYPER_SD, SIGMA_PRIOR_SD, GaussianHead
|
|
29
33
|
|
|
@@ -121,6 +121,36 @@ def _print_summary(s: dict) -> None:
|
|
|
121
121
|
f"(table in pymc_check.json)")
|
|
122
122
|
|
|
123
123
|
|
|
124
|
+
def _in_pymc_check(exc: BaseException) -> bool:
|
|
125
|
+
"""Whether `exc` was raised inside the `--full` PyMC check (check_pymc, pymc or pytensor)."""
|
|
126
|
+
tb = exc.__traceback__
|
|
127
|
+
while tb is not None:
|
|
128
|
+
if tb.tb_frame.f_globals.get("__name__") == "loopmath.belief.check_pymc":
|
|
129
|
+
return True
|
|
130
|
+
tb = tb.tb_next
|
|
131
|
+
return False
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _pymc_check_failed(home: Path, exc: BaseException) -> int:
|
|
135
|
+
"""`fit --full` whose PyMC check failed (a compiler error, say): remove the unfinished fit
|
|
136
|
+
folder and say what happened in one line, without a traceback."""
|
|
137
|
+
from .fit import FitBusy, fit_lock, remove_partials
|
|
138
|
+
|
|
139
|
+
try:
|
|
140
|
+
with fit_lock(home, LOCK_WAIT_S): # under the lock every .partial is from a fit that stopped
|
|
141
|
+
remove_partials(home)
|
|
142
|
+
except FitBusy:
|
|
143
|
+
pass # the next fit removes it
|
|
144
|
+
lines = [ln.strip() for ln in str(exc).splitlines() if ln.strip()]
|
|
145
|
+
said = ([ln for ln in lines if ln.startswith("ld:")] # the linker's reason, then the first compiler error
|
|
146
|
+
or [ln for ln in lines if ln.startswith("error:") or " error: " in ln])
|
|
147
|
+
detail = (said[0] if said else (lines or [type(exc).__name__])[-1])[:200]
|
|
148
|
+
kind = "could not compile its model on this machine" if type(exc).__name__ == "CompileError" else "stopped"
|
|
149
|
+
return output.fail(f"fit --full: the PyMC check {kind} ({type(exc).__name__}: {detail}). No fit was "
|
|
150
|
+
"written and fits/latest did not move; loopmath fit without --full fits as usual.",
|
|
151
|
+
output.EXIT_USER)
|
|
152
|
+
|
|
153
|
+
|
|
124
154
|
def fit(args: argparse.Namespace) -> int:
|
|
125
155
|
home = output.home(getattr(args, "home", None))
|
|
126
156
|
without = tuple(getattr(args, "without", None) or ())
|
|
@@ -140,10 +170,16 @@ def fit(args: argparse.Namespace) -> int:
|
|
|
140
170
|
else:
|
|
141
171
|
print(f"fit queued: {started.get('reason', 'a fit is running')}")
|
|
142
172
|
return output.EXIT_OK
|
|
173
|
+
import contextlib
|
|
174
|
+
import sys
|
|
175
|
+
|
|
143
176
|
from .fit import FitBusy, NothingToFit, UnknownSource, fit as run_fit
|
|
144
177
|
|
|
178
|
+
# --full: a failed compile makes pytensor print where it left the C code on stdout, which is for the result
|
|
179
|
+
quiet = contextlib.redirect_stdout(sys.stderr) if full else contextlib.nullcontext()
|
|
145
180
|
try:
|
|
146
|
-
|
|
181
|
+
with quiet:
|
|
182
|
+
path = run_fit(home, no_prior=no_prior, without=without, full=full, wait_s=LOCK_WAIT_S)
|
|
147
183
|
except FitBusy:
|
|
148
184
|
return output.fail(f"another fit has held {home / 'fits'} for more than {int(LOCK_WAIT_S)} s; "
|
|
149
185
|
"try again later or use --background", output.EXIT_LOCKED)
|
|
@@ -151,6 +187,10 @@ def fit(args: argparse.Namespace) -> int:
|
|
|
151
187
|
return output.fail(str(exc), output.EXIT_NOT_FOUND)
|
|
152
188
|
except NothingToFit as exc:
|
|
153
189
|
return output.fail(str(exc), output.EXIT_USER)
|
|
190
|
+
except Exception as exc:
|
|
191
|
+
if not (full and _in_pymc_check(exc)):
|
|
192
|
+
raise
|
|
193
|
+
return _pymc_check_failed(home, exc)
|
|
154
194
|
summary = _summary(path)
|
|
155
195
|
if as_json:
|
|
156
196
|
output.emit_json(SCHEMA, summary)
|
|
@@ -464,10 +464,12 @@ def source_label(doc: dict) -> str:
|
|
|
464
464
|
ext = run.get("ext") or {}
|
|
465
465
|
share = ext.get("dev.loopmath.share")
|
|
466
466
|
if isinstance(share, dict):
|
|
467
|
-
# the importer writes `source` and `task.org` as `shared:<org_hash>` already: never prefix twice
|
|
467
|
+
# the importer writes `source` and `task.org` as `shared:<org_hash>` already: never prefix twice. With no
|
|
468
|
+
# org at all the source is `shared`, the name `fit --without shared` takes (0.2.3, 22X review N1)
|
|
468
469
|
org = (share.get("source") or share.get("org") or share.get("org_hash") or (run.get("task") or {}).get("org")
|
|
469
|
-
or "
|
|
470
|
-
|
|
470
|
+
or "")
|
|
471
|
+
name = str(org).removeprefix("shared:")
|
|
472
|
+
return f"shared:{name}" if name and name != "shared" else "shared"
|
|
471
473
|
src = (run.get("task") or {}).get("source")
|
|
472
474
|
kind = src.get("kind") if isinstance(src, dict) else src
|
|
473
475
|
kind = str(kind or "").strip().lower()
|
|
@@ -72,7 +72,7 @@ REASON_NOTES = {
|
|
|
72
72
|
"attempt without usable cost": "crashed or no usage reported",
|
|
73
73
|
"attempt outside the workflow": "a model attempt at no piece of the run's workflow",
|
|
74
74
|
"duplicate run id": "the same run found twice",
|
|
75
|
-
SHIPPED_COPY: "
|
|
75
|
+
SHIPPED_COPY: "this run ships with loopmath and is also in your store, so it counts once, as yours",
|
|
76
76
|
"no configuration": "the run records no workflow and settings",
|
|
77
77
|
"workflow ref not resolved": "a workflow this version does not know",
|
|
78
78
|
"workflow has no pieces": "an empty workflow",
|
|
@@ -526,7 +526,8 @@ def fit(home: Path, *, no_prior: bool = False, without: tuple[str, ...] = (), fu
|
|
|
526
526
|
with fit_lock(home, wait_s):
|
|
527
527
|
remove_partials(home)
|
|
528
528
|
config = _read_config(home)
|
|
529
|
-
|
|
529
|
+
raw_weight = config.get("benchmark_prior_weight") # unset: each benchmark's own weight (spec 04 section 5)
|
|
530
|
+
weight = None if raw_weight is None else float(raw_weight)
|
|
530
531
|
try:
|
|
531
532
|
features, features_error = FeatureSet.from_config(config.get("features")), None
|
|
532
533
|
except FeatureConfigError as exc: # a hand-edited config.toml: fit with the built-ins, say why
|
|
@@ -550,9 +551,10 @@ def fit(home: Path, *, no_prior: bool = False, without: tuple[str, ...] = (), fu
|
|
|
550
551
|
raise UnknownSource(unknown_source_message(unknown, known))
|
|
551
552
|
if not any(hr.rows for hr in heads_rows.values()):
|
|
552
553
|
raise NothingToFit(_nothing_to_fit(no_prior, without, dropped))
|
|
553
|
-
specs = []
|
|
554
|
+
specs, bench_weights = [], {}
|
|
554
555
|
if not no_prior and "benchmark" not in without:
|
|
555
556
|
specs = prior_data.benchmark_factors(benchmarks, weight=weight)
|
|
557
|
+
bench_weights = prior_data.benchmark_weights(benchmarks, weight=weight)
|
|
556
558
|
seed_key = input_key(heads_rows, specs, {"no_prior": no_prior, "without": sorted(without), "eb": eb,
|
|
557
559
|
"benchmark_prior_weight": weight})
|
|
558
560
|
forest = Forest()
|
|
@@ -604,7 +606,7 @@ def fit(home: Path, *, no_prior: bool = False, without: tuple[str, ...] = (), fu
|
|
|
604
606
|
"seed_key": seed_key, "timebox_effort": design_rows.TIMEBOX_EFFORT_COST,
|
|
605
607
|
"timebox_terms": list(design_rows.TIMEBOX_LEVELS),
|
|
606
608
|
"options": {"no_prior": no_prior, "without": list(without), "full": full, "eb": eb,
|
|
607
|
-
"benchmark_prior_weight": weight},
|
|
609
|
+
"benchmark_prior_weight": weight, "benchmark_weights": bench_weights},
|
|
608
610
|
"runs_by_source": runs_by_source,
|
|
609
611
|
"n_runs": {"prior": sum(v for k, v in runs_by_source.items() if k != "user"),
|
|
610
612
|
"user": runs_by_source.get("user", 0)},
|