cmpnd 0.66.0__tar.gz → 0.68.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 (403) hide show
  1. {cmpnd-0.66.0 → cmpnd-0.68.0}/AGENTS.md +5 -2
  2. {cmpnd-0.66.0 → cmpnd-0.68.0}/PKG-INFO +7 -1
  3. {cmpnd-0.66.0 → cmpnd-0.68.0}/README.md +6 -0
  4. cmpnd-0.68.0/cmpnd/_deployments.py +105 -0
  5. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/__init__.py +5 -1
  6. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/commands/programs.py +45 -0
  7. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/commands/provider_credentials.py +4 -4
  8. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/commands/tool_servers.py +10 -10
  9. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/commands/top.py +24 -6
  10. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/verbs.py +8 -4
  11. cmpnd-0.68.0/cmpnd/cli/views.py +25 -0
  12. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/client.py +41 -0
  13. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/deployment.py +1 -1
  14. {cmpnd-0.66.0 → cmpnd-0.68.0}/docs/cli.md +48 -12
  15. {cmpnd-0.66.0 → cmpnd-0.68.0}/docs/client.md +7 -2
  16. {cmpnd-0.66.0 → cmpnd-0.68.0}/pyproject.toml +5 -5
  17. {cmpnd-0.66.0 → cmpnd-0.68.0}/scripts/capture_review_run.py +1 -1
  18. cmpnd-0.68.0/scripts/release-gate.sh +11 -0
  19. cmpnd-0.68.0/scripts/release-real-models.sh +15 -0
  20. {cmpnd-0.66.0 → cmpnd-0.68.0}/scripts/seed_review_run.py +147 -67
  21. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/committee_task.py +2 -2
  22. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/conftest.py +3 -3
  23. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_assessments_cli.py +4 -9
  24. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_deploy_programs.py +1 -1
  25. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_optimize_loop.py +2 -2
  26. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_optimize_review_committee.py +1 -1
  27. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_valsets_cli.py +6 -10
  28. {cmpnd-0.66.0/tests/stress → cmpnd-0.68.0/tests/real_models}/_provider.py +1 -1
  29. {cmpnd-0.66.0/tests/stress → cmpnd-0.68.0/tests/real_models}/mint_bedrock_token.py +2 -2
  30. {cmpnd-0.66.0/tests/stress → cmpnd-0.68.0/tests/real_models}/test_bedrock_converse.py +2 -2
  31. {cmpnd-0.66.0/tests/stress → cmpnd-0.68.0/tests/real_models}/test_deploy_programs.py +3 -3
  32. {cmpnd-0.66.0/tests/stress → cmpnd-0.68.0/tests/real_models}/test_multi_client_stress.py +3 -3
  33. {cmpnd-0.66.0/tests/stress → cmpnd-0.68.0/tests/real_models}/test_optimize_client_committee.py +2 -2
  34. {cmpnd-0.66.0/tests/stress → cmpnd-0.68.0/tests/real_models}/test_optimize_continuation.py +2 -2
  35. {cmpnd-0.66.0/tests/stress → cmpnd-0.68.0/tests/real_models}/test_optimize_loop.py +6 -6
  36. {cmpnd-0.66.0/tests/stress → cmpnd-0.68.0/tests/real_models}/test_optimize_loop_wasm.py +6 -6
  37. {cmpnd-0.66.0/tests/stress → cmpnd-0.68.0/tests/real_models}/test_optimize_stress.py +3 -3
  38. {cmpnd-0.66.0/tests/stress → cmpnd-0.68.0/tests/real_models}/test_provider_roles.py +2 -2
  39. {cmpnd-0.66.0/tests/stress → cmpnd-0.68.0/tests/real_models}/test_readiness.py +2 -2
  40. {cmpnd-0.66.0/tests/stress → cmpnd-0.68.0/tests/real_models}/test_real_provider_twins.py +3 -3
  41. {cmpnd-0.66.0/tests/stress → cmpnd-0.68.0/tests/real_models}/test_reliability.py +1 -1
  42. {cmpnd-0.66.0/tests/stress → cmpnd-0.68.0/tests/real_models}/test_reliability_classify.py +1 -1
  43. {cmpnd-0.66.0/tests/stress → cmpnd-0.68.0/tests/real_models}/test_rlm_wasm.py +7 -3
  44. {cmpnd-0.66.0/tests/stress → cmpnd-0.68.0/tests/real_models}/test_trace_search.py +1 -1
  45. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_authored.py +1 -1
  46. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_main.py +9 -0
  47. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_parity.py +78 -0
  48. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_programs.py +77 -0
  49. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_provider_credentials.py +19 -5
  50. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_tool_servers.py +29 -7
  51. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_client.py +59 -0
  52. cmpnd-0.68.0/tests/test_deployments_read.py +161 -0
  53. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_multi_client_stress_readiness.py +1 -1
  54. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_optimize_lift.py +1 -1
  55. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_real_provider_twins_readiness.py +1 -1
  56. cmpnd-0.68.0/tests/test_release_gate_script.py +11 -0
  57. cmpnd-0.68.0/tests/test_release_real_models_script.py +15 -0
  58. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_seed_review_run.py +106 -2
  59. {cmpnd-0.66.0 → cmpnd-0.68.0}/uv.lock +1 -1
  60. cmpnd-0.66.0/cmpnd/_deployments.py +0 -37
  61. cmpnd-0.66.0/scripts/release-stress.sh +0 -14
  62. cmpnd-0.66.0/tests/test_deployments_read.py +0 -41
  63. cmpnd-0.66.0/tests/test_release_stress_script.py +0 -14
  64. {cmpnd-0.66.0 → cmpnd-0.68.0}/.gitignore +0 -0
  65. {cmpnd-0.66.0 → cmpnd-0.68.0}/CLAUDE.md +0 -0
  66. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/__init__.py +0 -0
  67. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/_assessments.py +0 -0
  68. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/_authored_import.py +0 -0
  69. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/_exporter_pool.py +0 -0
  70. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/_gepa_patch.py +0 -0
  71. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/_http.py +0 -0
  72. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/_program_patch.py +0 -0
  73. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/_rlm_patch.py +0 -0
  74. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/_runtime_tools.py +0 -0
  75. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/_timespec.py +0 -0
  76. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/_traces.py +0 -0
  77. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/_valsets.py +0 -0
  78. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/authored.py +0 -0
  79. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/callback.py +0 -0
  80. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/api_client.py +0 -0
  81. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/commands/__init__.py +0 -0
  82. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/commands/admin.py +0 -0
  83. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/commands/assessments.py +0 -0
  84. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/commands/auth.py +0 -0
  85. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/commands/datasets.py +0 -0
  86. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/commands/deployments.py +0 -0
  87. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/commands/evals.py +0 -0
  88. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/commands/login.py +0 -0
  89. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/commands/optimizations.py +0 -0
  90. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/commands/org.py +0 -0
  91. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/commands/traces.py +0 -0
  92. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/commands/valsets.py +0 -0
  93. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/credentials.py +0 -0
  94. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/deprecation.py +0 -0
  95. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/pagination.py +0 -0
  96. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/shell.py +0 -0
  97. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/trace_render.py +0 -0
  98. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/cli/tree_help.py +0 -0
  99. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/configuration.py +0 -0
  100. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/context.py +0 -0
  101. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/credentials.py +0 -0
  102. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/dataset_sync.py +0 -0
  103. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/datasets.py +0 -0
  104. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/decorators.py +0 -0
  105. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/deployment_metadata.py +0 -0
  106. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/deployment_runs.py +0 -0
  107. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/eval_handler.py +0 -0
  108. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/execution.py +0 -0
  109. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/exporter.py +0 -0
  110. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/exporter_http.py +0 -0
  111. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/helpers.py +0 -0
  112. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/identity.py +0 -0
  113. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/imaging.py +0 -0
  114. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/ir/__init__.py +0 -0
  115. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/ir/decode.py +0 -0
  116. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/ir/encode.py +0 -0
  117. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/ir/hash.py +0 -0
  118. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/ir/program.py +0 -0
  119. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/ir/reflection.py +0 -0
  120. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/ir/types.py +0 -0
  121. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/ir/xxh64.py +0 -0
  122. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/lm_configuration.py +0 -0
  123. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/mcp_servers.py +0 -0
  124. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/models.py +0 -0
  125. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/named_programs.py +0 -0
  126. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/optimization.py +0 -0
  127. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/optimizers/__init__.py +0 -0
  128. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/optimizers/gepa.py +0 -0
  129. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/optimizers/gepa_callback.py +0 -0
  130. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/optimizers/resume.py +0 -0
  131. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/optimizers/tracker.py +0 -0
  132. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/packaging.py +0 -0
  133. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/programs.py +0 -0
  134. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/references.py +0 -0
  135. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/retry.py +0 -0
  136. {cmpnd-0.66.0 → cmpnd-0.68.0}/cmpnd/traces.py +0 -0
  137. {cmpnd-0.66.0 → cmpnd-0.68.0}/docs/2026-04-02-code-review.md +0 -0
  138. {cmpnd-0.66.0 → cmpnd-0.68.0}/docs/custom-proposer.md +0 -0
  139. {cmpnd-0.66.0 → cmpnd-0.68.0}/docs/plans/2026-04-05-train-val-dataset-capture-design.md +0 -0
  140. {cmpnd-0.66.0 → cmpnd-0.68.0}/docs/plans/2026-04-05-train-val-dataset-capture.md +0 -0
  141. {cmpnd-0.66.0 → cmpnd-0.68.0}/docs/reading-traces.md +0 -0
  142. {cmpnd-0.66.0 → cmpnd-0.68.0}/docs/sdk-instrumentation.md +0 -0
  143. {cmpnd-0.66.0 → cmpnd-0.68.0}/examples/generalizing_proposer.py +0 -0
  144. {cmpnd-0.66.0 → cmpnd-0.68.0}/examples/local_ollama.py +0 -0
  145. {cmpnd-0.66.0 → cmpnd-0.68.0}/ingest/LINEAGE.md +0 -0
  146. {cmpnd-0.66.0 → cmpnd-0.68.0}/ingest/README.md +0 -0
  147. {cmpnd-0.66.0 → cmpnd-0.68.0}/ingest/cmpnd_ingest/__init__.py +0 -0
  148. {cmpnd-0.66.0 → cmpnd-0.68.0}/ingest/cmpnd_ingest/bodies.py +0 -0
  149. {cmpnd-0.66.0 → cmpnd-0.68.0}/ingest/cmpnd_ingest/client_floor.py +0 -0
  150. {cmpnd-0.66.0 → cmpnd-0.68.0}/ingest/cmpnd_ingest/exporter_http.py +0 -0
  151. {cmpnd-0.66.0 → cmpnd-0.68.0}/ingest/cmpnd_ingest/program_names.py +0 -0
  152. {cmpnd-0.66.0 → cmpnd-0.68.0}/ingest/cmpnd_ingest/protocols.py +0 -0
  153. {cmpnd-0.66.0 → cmpnd-0.68.0}/ingest/cmpnd_ingest/py.typed +0 -0
  154. {cmpnd-0.66.0 → cmpnd-0.68.0}/ingest/cmpnd_ingest/request_log.py +0 -0
  155. {cmpnd-0.66.0 → cmpnd-0.68.0}/ingest/cmpnd_ingest/retry.py +0 -0
  156. {cmpnd-0.66.0 → cmpnd-0.68.0}/ingest/cmpnd_ingest/trace_facts.py +0 -0
  157. {cmpnd-0.66.0 → cmpnd-0.68.0}/ingest/pyproject.toml +0 -0
  158. {cmpnd-0.66.0 → cmpnd-0.68.0}/scripts/audit-sdist.sh +0 -0
  159. {cmpnd-0.66.0 → cmpnd-0.68.0}/scripts/check-pip-install.sh +0 -0
  160. {cmpnd-0.66.0 → cmpnd-0.68.0}/scripts/check_release_artifacts.py +0 -0
  161. {cmpnd-0.66.0 → cmpnd-0.68.0}/scripts/fixtures/review_run.json.gz +0 -0
  162. {cmpnd-0.66.0 → cmpnd-0.68.0}/scripts/gepa_resume_bug.py +0 -0
  163. {cmpnd-0.66.0 → cmpnd-0.68.0}/scripts/install-test-env.sh +0 -0
  164. {cmpnd-0.66.0 → cmpnd-0.68.0}/scripts/require_version_bump.py +0 -0
  165. {cmpnd-0.66.0 → cmpnd-0.68.0}/scripts/selfhost_compat.py +0 -0
  166. {cmpnd-0.66.0 → cmpnd-0.68.0}/scripts/test-in-linux.sh +0 -0
  167. {cmpnd-0.66.0 → cmpnd-0.68.0}/stubs/dspy/__init__.pyi +0 -0
  168. {cmpnd-0.66.0 → cmpnd-0.68.0}/stubs/dspy/primitives/__init__.pyi +0 -0
  169. {cmpnd-0.66.0 → cmpnd-0.68.0}/stubs/dspy/primitives/prediction.pyi +0 -0
  170. {cmpnd-0.66.0 → cmpnd-0.68.0}/stubs/dspy/utils/__init__.pyi +0 -0
  171. {cmpnd-0.66.0 → cmpnd-0.68.0}/stubs/dspy/utils/callback.pyi +0 -0
  172. {cmpnd-0.66.0 → cmpnd-0.68.0}/stubs/dspy/utils/dummies.pyi +0 -0
  173. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/__init__.py +0 -0
  174. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/_credential_route.py +0 -0
  175. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/_deployment_signature_helpers.py +0 -0
  176. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/_exporter_helpers.py +0 -0
  177. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/_fake_clock.py +0 -0
  178. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/_identity_helpers.py +0 -0
  179. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/_resolve_refs.py +0 -0
  180. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/_traced_run.py +0 -0
  181. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/conftest.py +0 -0
  182. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/__init__.py +0 -0
  183. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/continuation_task.py +0 -0
  184. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/data/committee_train.ndjson.gz +0 -0
  185. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/data/committee_val.ndjson.gz +0 -0
  186. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/fake_lm.py +0 -0
  187. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/helpers.py +0 -0
  188. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/target_capabilities.py +0 -0
  189. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_capture_prompts.py +0 -0
  190. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_composite_module.py +0 -0
  191. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_dataset_auto_creation.py +0 -0
  192. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_deploy_execute.py +0 -0
  193. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_deploy_pandas.py +0 -0
  194. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_edge_cases.py +0 -0
  195. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_example_hash.py +0 -0
  196. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_gepa_optimization.py +0 -0
  197. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_interpreter_spans.py +0 -0
  198. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_lm_accuracy.py +0 -0
  199. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_module_tracing.py +0 -0
  200. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_optimization_lineage.py +0 -0
  201. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_optimization_metric_identity.py +0 -0
  202. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_optimize_authored_metric.py +0 -0
  203. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_optimize_continuation.py +0 -0
  204. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_optimize_custom_proposer.py +0 -0
  205. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_optimize_failures.py +0 -0
  206. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_optimize_server_owned_completion.py +0 -0
  207. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_parallel_export.py +0 -0
  208. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_project_attribution.py +0 -0
  209. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_react_tool_spans.py +0 -0
  210. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_save_load.py +0 -0
  211. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_trace_structure.py +0 -0
  212. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_traces_read.py +0 -0
  213. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/e2e/test_user_attribution.py +0 -0
  214. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/identity_vectors/01_predict_qa.json +0 -0
  215. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/identity_vectors/02_predict_renamed_field.json +0 -0
  216. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/identity_vectors/03_chain_of_thought_qa.json +0 -0
  217. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/identity_vectors/04_predict_richer_types.json +0 -0
  218. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/identity_vectors/05_composite_two_predicts.json +0 -0
  219. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/identity_vectors/06_multichaincomparison.json +0 -0
  220. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/identity_vectors/07_program_of_thought.json +0 -0
  221. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/identity_vectors/08_opaque_module.json +0 -0
  222. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/identity_vectors/09_predict_pydantic_field.json +0 -0
  223. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/identity_vectors/10_react.json +0 -0
  224. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/identity_vectors/11_refine.json +0 -0
  225. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/identity_vectors/12_retrieve.json +0 -0
  226. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/identity_vectors/13_knn.json +0 -0
  227. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/identity_vectors/14_parallel.json +0 -0
  228. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/identity_vectors/README.md +0 -0
  229. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/ingest_conformance.py +0 -0
  230. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/integration/__init__.py +0 -0
  231. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/integration/authored_optimize/judge.py +0 -0
  232. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/integration/authored_optimize/optimize_hosted.py +0 -0
  233. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/integration/conftest.py +0 -0
  234. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/integration/hosted_mcp_tool_optimize_probe.py +0 -0
  235. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/integration/hosted_optimize_probe.py +0 -0
  236. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/integration/optimization_run_probe.py +0 -0
  237. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/integration/test_cli_deploy_smoketest.py +0 -0
  238. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/integration/test_logs_renders_traces.py +0 -0
  239. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/integration/test_optimization_run.py +0 -0
  240. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/integration/test_optimizing_progress.py +0 -0
  241. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/integration/test_unhappy_path.py +0 -0
  242. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/load/__init__.py +0 -0
  243. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/load/__main__.py +0 -0
  244. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/load/drain.py +0 -0
  245. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/load/ingest.py +0 -0
  246. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/load/latency_transport.py +0 -0
  247. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/load/rlm_shape.py +0 -0
  248. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/load/rlm_size_report.py +0 -0
  249. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/load/sweep.py +0 -0
  250. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/load/test_rlm_shape.py +0 -0
  251. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/load/test_rlm_size_report.py +0 -0
  252. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/parity/__init__.py +0 -0
  253. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/parity/conftest.py +0 -0
  254. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/parity/seed_parity.py +0 -0
  255. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/parity/test_auth.py +0 -0
  256. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/parity/test_datasets.py +0 -0
  257. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/parity/test_deployments.py +0 -0
  258. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/parity/test_evals.py +0 -0
  259. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/parity/test_health.py +0 -0
  260. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/parity/test_modules.py +0 -0
  261. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/parity/test_optimizations.py +0 -0
  262. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/parity/test_programs.py +0 -0
  263. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/parity/test_signatures.py +0 -0
  264. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/parity/test_trace_streaming.py +0 -0
  265. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/parity/test_traces.py +0 -0
  266. {cmpnd-0.66.0/tests/stress → cmpnd-0.68.0/tests/real_models}/__init__.py +0 -0
  267. {cmpnd-0.66.0/tests/stress → cmpnd-0.68.0/tests/real_models}/_readiness.py +0 -0
  268. {cmpnd-0.66.0/tests/stress → cmpnd-0.68.0/tests/real_models}/_reliability.py +0 -0
  269. {cmpnd-0.66.0/tests/stress → cmpnd-0.68.0/tests/real_models}/_result.py +0 -0
  270. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/span_reference_fixture.py +0 -0
  271. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_adapter_reentrancy.py +0 -0
  272. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_assessments_api.py +0 -0
  273. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_authored_binding_credentials.py +0 -0
  274. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_authored_bundle_collisions.py +0 -0
  275. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_authored_metric_contract.py +0 -0
  276. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_authored_named_models.py +0 -0
  277. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_authored_optimize.py +0 -0
  278. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_callback.py +0 -0
  279. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_candidate_lineage.py +0 -0
  280. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/__init__.py +0 -0
  281. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/conftest.py +0 -0
  282. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_admin.py +0 -0
  283. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_api_client.py +0 -0
  284. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_assessments.py +0 -0
  285. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_auth.py +0 -0
  286. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_credentials.py +0 -0
  287. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_datasets.py +0 -0
  288. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_deployment_runs.py +0 -0
  289. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_deployments.py +0 -0
  290. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_evals.py +0 -0
  291. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_login.py +0 -0
  292. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_optimizations.py +0 -0
  293. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_org.py +0 -0
  294. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_pagination.py +0 -0
  295. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_schema_sample.py +0 -0
  296. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_shell.py +0 -0
  297. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_top.py +0 -0
  298. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_traces.py +0 -0
  299. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_traces_program_and_module.py +0 -0
  300. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_traces_search_wire.py +0 -0
  301. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_tree_help.py +0 -0
  302. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cli/test_valsets.py +0 -0
  303. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_client_floor.py +0 -0
  304. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_client_program_names.py +0 -0
  305. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_clustering/__init__.py +0 -0
  306. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_clustering/conftest.py +0 -0
  307. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_clustering/test_edge_cases.py +0 -0
  308. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_clustering/test_hash_consistency.py +0 -0
  309. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_clustering/test_type_conversion.py +0 -0
  310. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_cmp551_grouping_identity.py +0 -0
  311. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_configuration.py +0 -0
  312. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_context.py +0 -0
  313. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_context_propagation.py +0 -0
  314. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_credential_kwargs.py +0 -0
  315. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_credential_selection.py +0 -0
  316. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_credential_values.py +0 -0
  317. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_dataset_polling.py +0 -0
  318. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_dataset_sync.py +0 -0
  319. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_datasets.py +0 -0
  320. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_decision_client_spans.py +0 -0
  321. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_decorators.py +0 -0
  322. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_deploy.py +0 -0
  323. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_deploy_mcp_tool_references.py +0 -0
  324. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_deploy_program_id.py +0 -0
  325. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_deployment_metadata.py +0 -0
  326. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_deployment_runs.py +0 -0
  327. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_eval.py +0 -0
  328. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_eval_example_attribution.py +0 -0
  329. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_eval_start.py +0 -0
  330. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_eval_trace_grouping.py +0 -0
  331. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_exception_paths.py +0 -0
  332. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_execute.py +0 -0
  333. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_execute_run_identity.py +0 -0
  334. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_exporter.py +0 -0
  335. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_exporter_program_names.py +0 -0
  336. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_exporter_queue.py +0 -0
  337. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_exporter_real.py +0 -0
  338. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_fake_lm.py +0 -0
  339. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_gepa_callback.py +0 -0
  340. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_gepa_integration.py +0 -0
  341. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_gepa_output_normalization.py +0 -0
  342. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_gepa_resume.py +0 -0
  343. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_identity.py +0 -0
  344. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_imaging.py +0 -0
  345. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_import_weight.py +0 -0
  346. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_ingest_conformance.py +0 -0
  347. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_ingest_second_producer.py +0 -0
  348. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_integration.py +0 -0
  349. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_interpreter_callback.py +0 -0
  350. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_ir_encoder_properties.py +0 -0
  351. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_ir_golden_vectors.py +0 -0
  352. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_ir_roundtrip.py +0 -0
  353. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_lm15_native_calls.py +0 -0
  354. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_lm_configuration.py +0 -0
  355. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_lm_usage_shapes.py +0 -0
  356. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_mcp_tools.py +0 -0
  357. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_models.py +0 -0
  358. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_optimization_progress.py +0 -0
  359. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_optimization_start.py +0 -0
  360. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_optimize.py +0 -0
  361. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_optimize_budget.py +0 -0
  362. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_optimize_lms.py +0 -0
  363. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_optimize_proposer.py +0 -0
  364. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_optimize_reflection_lm.py +0 -0
  365. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_optimize_terminal_failure.py +0 -0
  366. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_packaging.py +0 -0
  367. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_packaging_callable_source.py +0 -0
  368. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_packaging_mcp_tools.py +0 -0
  369. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_packaging_program_source.py +0 -0
  370. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_poll_until.py +0 -0
  371. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_program_id_deprecation.py +0 -0
  372. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_program_identity.py +0 -0
  373. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_program_lineage_persist.py +0 -0
  374. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_program_names_in_deploy.py +0 -0
  375. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_programs_create.py +0 -0
  376. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_project_payload.py +0 -0
  377. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_reflector_properties.py +0 -0
  378. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_reflector_smoke.py +0 -0
  379. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_replaced_names.py +0 -0
  380. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_repro_reactv2_bugs.py +0 -0
  381. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_require_version_bump.py +0 -0
  382. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_retry.py +0 -0
  383. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_reversible_failures.py +0 -0
  384. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_rlm_patch.py +0 -0
  385. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_run_attribution_paths.py +0 -0
  386. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_runtime_tools.py +0 -0
  387. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_schemas.py +0 -0
  388. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_seal_lm_credential.py +0 -0
  389. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_signature_inputs.py +0 -0
  390. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_span_references.py +0 -0
  391. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_span_sent_once.py +0 -0
  392. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_system_one.py +0 -0
  393. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_trace_context_concurrency.py +0 -0
  394. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_trace_fact_wire_contract.py +0 -0
  395. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_trace_facts.py +0 -0
  396. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_trace_render.py +0 -0
  397. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_traces_read.py +0 -0
  398. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_tracked_gepa.py +0 -0
  399. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_tracker_enrich.py +0 -0
  400. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_truncation.py +0 -0
  401. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_upload_auth_headers.py +0 -0
  402. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_valsets_api.py +0 -0
  403. {cmpnd-0.66.0 → cmpnd-0.68.0}/tests/test_xxh64.py +0 -0
@@ -92,7 +92,7 @@ knowing:
92
92
  Run `uv lock` and commit the result. A stale lock makes every `uv` command
93
93
  rewrite it.
94
94
  - `basedpyright` takes no path argument. A path overrides pyproject's
95
- `include`, so `basedpyright cmpnd` skips `tests/e2e` and `tests/stress` and
95
+ `include`, so `basedpyright cmpnd` skips `tests/e2e` and `tests/real_models` and
96
96
  passes changes CI rejects.
97
97
 
98
98
  **This tree's SDK and CLI run against each live self-host release.**
@@ -234,7 +234,10 @@ first. Its failures name the attribute or class that moved.
234
234
 
235
235
  To add a verb to both front-ends, add a `Verb(...)` row to `cli/verbs.py`, add
236
236
  its `add_parser` call in `top.register()`, and add the entity method or the
237
- `_make_namespace` function. The parity test fails until all three agree.
237
+ `_make_namespace` function. The parity test fails until all three agree. A
238
+ verb that repeats a namespaced command sets `shortcut_for`, and its help then
239
+ starts with "Shortcut for `cmpnd deployments list`". The parity test checks
240
+ that the named command exists.
238
241
 
239
242
  When you touch a handler:
240
243
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: cmpnd
3
- Version: 0.66.0
3
+ Version: 0.68.0
4
4
  Summary: DSPy observability and deployment SDK for cmpnd
5
5
  Project-URL: Homepage, https://cmpnd.ai
6
6
  Author-email: cmpnd <hello@cmpnd.ai>
@@ -669,6 +669,12 @@ global config. Use it as a context manager or as a plain object.
669
669
  its best `DeployedProgram`.
670
670
  - `list_traces(**filters)` and `get_trace(trace_id)` read traces with the
671
671
  client's credentials. They flush the client's traces first.
672
+ - `list_deployments(status=None, since=None, limit=50, offset=0)` and
673
+ `get_deployment(deployment_id)` read deployment records, as
674
+ `cmpnd deployments list` and `show` do.
675
+ - `get_deployment_source(deployment_id, path=None)` returns the program file a
676
+ deployment stores, as `cmpnd inspect --source` does. A continuation's
677
+ deployment holds the program the continuation runs.
672
678
  - `close()` flushes the client's traces and closes the client. A closed
673
679
  client raises `RuntimeError` on every method.
674
680
 
@@ -618,6 +618,12 @@ global config. Use it as a context manager or as a plain object.
618
618
  its best `DeployedProgram`.
619
619
  - `list_traces(**filters)` and `get_trace(trace_id)` read traces with the
620
620
  client's credentials. They flush the client's traces first.
621
+ - `list_deployments(status=None, since=None, limit=50, offset=0)` and
622
+ `get_deployment(deployment_id)` read deployment records, as
623
+ `cmpnd deployments list` and `show` do.
624
+ - `get_deployment_source(deployment_id, path=None)` returns the program file a
625
+ deployment stores, as `cmpnd inspect --source` does. A continuation's
626
+ deployment holds the program the continuation runs.
621
627
  - `close()` flushes the client's traces and closes the client. A closed
622
628
  client raises `RuntimeError` on every method.
623
629
 
@@ -0,0 +1,105 @@
1
+ """Deployment reads behind ``cmpnd.Client``: the record list, one record, its stored source and its typed metadata."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import io
6
+ import tokenize
7
+ from typing import Any, Protocol
8
+
9
+ from . import _http
10
+ from .deployment_metadata import DeploymentMetadataError, DeploymentSignatureResponse
11
+
12
+ MAX_DEPLOYMENTS_PER_PAGE = 500
13
+
14
+
15
+ class _JSONReader(Protocol):
16
+ def get(self, path: str) -> Any: ...
17
+
18
+
19
+ def read_signature(client: _JSONReader, deployment_id: str) -> DeploymentSignatureResponse:
20
+ """Read one deployment's persisted signature through an existing client."""
21
+ value = client.get(f"/api/v1/deployments/{deployment_id}/signature")
22
+ response = DeploymentSignatureResponse.from_dict(value)
23
+ if response.deployment_id != deployment_id:
24
+ raise DeploymentMetadataError(
25
+ f"response deployment_id {response.deployment_id!r} does not match {deployment_id!r}"
26
+ )
27
+ return response
28
+
29
+
30
+ def get_signature(
31
+ deployment_id: str,
32
+ *,
33
+ api_key: str,
34
+ endpoint: str,
35
+ timeout: float | None = None,
36
+ ) -> DeploymentSignatureResponse:
37
+ """Read one deployment's persisted signature with explicit credentials."""
38
+ client = (
39
+ _http.ApiClient(api_key, endpoint) if timeout is None else _http.ApiClient(api_key, endpoint, timeout=timeout)
40
+ )
41
+ return read_signature(client, deployment_id)
42
+
43
+
44
+ def list_deployments(
45
+ *,
46
+ status: str | None = None,
47
+ since: str | None = None,
48
+ limit: int = 50,
49
+ offset: int = 0,
50
+ api_key: str,
51
+ endpoint: str,
52
+ ) -> dict[str, Any]:
53
+ """List the organization's deployments, newest first.
54
+
55
+ Returns ``{"deployments": [...], "has_more": bool, ...}``. ``status`` is one
56
+ of ``pending``, ``parsing``, ``optimizing``, ``ready`` or ``failed``, and
57
+ ``since`` is an ISO 8601 timestamp. The route pages by page number, so
58
+ ``offset`` must be a whole multiple of ``limit``. The route returns at most
59
+ 500 deployments per page, so ``limit`` must not exceed 500.
60
+ """
61
+ if limit <= 0:
62
+ raise _http.ApiError("limit must be positive")
63
+ if limit > MAX_DEPLOYMENTS_PER_PAGE:
64
+ raise _http.ApiError(
65
+ f"limit must not exceed {MAX_DEPLOYMENTS_PER_PAGE}; the deployments route returns at most "
66
+ f"{MAX_DEPLOYMENTS_PER_PAGE} per page"
67
+ )
68
+ if offset < 0:
69
+ raise _http.ApiError("offset must not be negative")
70
+ if offset % limit != 0:
71
+ lower = (offset // limit) * limit
72
+ raise _http.ApiError(
73
+ f"offset must be a multiple of limit (the deployments route pages by page number); "
74
+ f"try offset {lower} or {lower + limit}"
75
+ )
76
+ params = {"per_page": str(limit), "page": str(offset // limit + 1)}
77
+ if status is not None:
78
+ params["status"] = status
79
+ if since is not None:
80
+ params["since"] = since
81
+ return _http.ApiClient(api_key, endpoint).get("/api/v1/deployments", params=params)
82
+
83
+
84
+ def get_deployment(deployment_id: str, *, api_key: str, endpoint: str) -> dict[str, Any]:
85
+ """Read one deployment's record: its status, program, model and metadata."""
86
+ return _http.ApiClient(api_key, endpoint).get(f"/api/v1/deployments/{deployment_id}")
87
+
88
+
89
+ def get_source(deployment_id: str, *, path: str | None = None, api_key: str, endpoint: str) -> str:
90
+ """Read one file of a deployment's stored source as text.
91
+
92
+ Without ``path`` it reads the program file the stored bundle names. With
93
+ ``path`` it reads that archive-relative member. It decodes the file with the
94
+ encoding the file declares in a PEP 263 coding comment, and with UTF-8 when
95
+ the file declares none.
96
+ """
97
+ client = _http.ApiClient(api_key, endpoint)
98
+ route = f"/api/v1/deployments/{deployment_id}/source"
99
+ if path is None:
100
+ path = client.get(route).get("program")
101
+ if not path:
102
+ raise _http.ApiError(f"the stored source of deployment {deployment_id} names no program file")
103
+ raw = client.get_bytes(route, params={"path": path})
104
+ encoding, _lines = tokenize.detect_encoding(io.BytesIO(raw).readline)
105
+ return raw.decode(encoding)
@@ -107,7 +107,11 @@ def parse(parser: argparse.ArgumentParser, argv: list[str]) -> argparse.Namespac
107
107
  def main() -> None:
108
108
  parser = tree_help.TreeHelpParser(
109
109
  prog="cmpnd",
110
- description="CMPND platform CLI — deploy, run, and inspect DSPy programs.",
110
+ description=(
111
+ "CMPND platform CLI — deploy, run, and inspect DSPy programs.\n\n"
112
+ "The top-level commands are the Docker-style deploy-and-run loop. ps, run and inspect are\n"
113
+ "shortcuts for deployments list, run and show."
114
+ ),
111
115
  epilog=_EPILOG,
112
116
  formatter_class=argparse.RawDescriptionHelpFormatter,
113
117
  )
@@ -207,6 +207,19 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
207
207
  purge.add_argument("--force", action="store_true", help="Skip the confirmation (required when not on a terminal)")
208
208
  purge.set_defaults(func=handle_purge)
209
209
 
210
+ rename = sub.add_parser(
211
+ "rename",
212
+ help="Name or rename a program",
213
+ description=(
214
+ "Make NAME the current name of PROGRAM. The name it had keeps resolving to it, so code that still "
215
+ "declares the old name reaches the same program, with its id and history. A name another program "
216
+ "answers to is refused."
217
+ ),
218
+ )
219
+ rename.add_argument("program", metavar="PROGRAM", help="Program name or p_ id")
220
+ rename.add_argument("new_name", metavar="NAME", help="The program's new name, unique in your organization")
221
+ rename.set_defaults(func=handle_rename)
222
+
210
223
  select = sub.add_parser("select", help="Pin an optimization run as this program's chosen version")
211
224
  select.add_argument("id", help=_COMPILED_HASH_HELP)
212
225
  select.add_argument("--run", dest="run_id", required=True, help="Optimization run ID (op_...) to pin")
@@ -624,6 +637,38 @@ def handle_purge(client: api_client.ApiClient, args: Any) -> Any:
624
637
  return _trash_write(client, f"/api/v1/programs/{program_id}/purge")
625
638
 
626
639
 
640
+ def handle_rename(client: api_client.ApiClient, args: Any) -> Any:
641
+ """Make ``args.new_name`` the current name of the program ``args.program`` names, keeping its id."""
642
+ from ... import programs
643
+ from . import top
644
+
645
+ try:
646
+ programs.validate_program_name(args.new_name)
647
+ except ValueError as exc:
648
+ raise api_client.CliError(str(exc)) from exc
649
+ program_id, trashed = resolve(client, args.program, old_server_remedy=_rename_remedy())
650
+ if trashed:
651
+ raise api_client.CliError(
652
+ f"{args.program} is in the Trash. Restore it with `{top.hint_programs('restore', args.program)}` "
653
+ "before you rename it."
654
+ )
655
+ try:
656
+ return client.post(f"/api/v1/programs/{program_id}/rename", json={"name": args.new_name})
657
+ except api_client.CliError as exc:
658
+ # A server from before the rename route answers 405, because its GET dispatcher owns the path.
659
+ if exc.status_code == 405:
660
+ _refuse_if_old(client, exc, _rename_remedy(program_id))
661
+ raise api_client.CliError(
662
+ f"this cmpnd server predates renaming a program through the API. {_rename_remedy(program_id)}"
663
+ ) from exc
664
+ raise
665
+
666
+
667
+ def _rename_remedy(program_id: str = "") -> str:
668
+ where = f"on its page in the web app, at /ui/programs/{program_id}" if program_id else "in the web app"
669
+ return f"Rename the program {where}, or upgrade the server."
670
+
671
+
627
672
  def _trash_listing(client: api_client.ApiClient) -> Any:
628
673
  """GET the Trash. On a server from before the Trash API it answers 404, which is the old-server signal."""
629
674
  try:
@@ -5,7 +5,7 @@ platform spend on your behalf when a program of yours runs?
5
5
 
6
6
  cmpnd credentials create --name luna-exec --preset lunaroute # a model provider
7
7
  cmpnd credentials create --kind mcp --server URL --name n … # an MCP tool server
8
- cmpnd credentials list
8
+ cmpnd credentials list --text
9
9
  cmpnd credentials protocols luna-exec --add system_one
10
10
  cmpnd credentials default luna-exec
11
11
  cmpnd credentials delete --name luna-exec --force
@@ -70,7 +70,7 @@ import sys
70
70
  from argparse import ArgumentParser, _SubParsersAction
71
71
  from typing import Any
72
72
 
73
- from .. import api_client, deprecation
73
+ from .. import api_client, deprecation, views
74
74
 
75
75
  #: The placements the platform's credentialed egress can compose a credential into.
76
76
  #: Closed set, and the same three strings `cmpnd.mcp_tools`'s auth shapes record.
@@ -156,7 +156,7 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
156
156
  deprecation.alias(sub, "add", "create", func=handle_create, configure=_seal_args)
157
157
 
158
158
  listing = sub.add_parser("list", help="Show your org's credentials, their protocols and the default")
159
- listing.add_argument("--json", action="store_true", help="Emit the raw JSON instead of the rendering")
159
+ views.add_text_flag(listing)
160
160
  listing.set_defaults(func=handle_list)
161
161
 
162
162
  protocols = sub.add_parser(
@@ -393,7 +393,7 @@ def handle_list(client: api_client.ApiClient, args: Any) -> Any:
393
393
  # Metadata only: the platform's projection carries no key material, not even its
394
394
  # length, so there is nothing here to redact.
395
395
  payload = client.get(_ROOT)
396
- if getattr(args, "json", False) or not isinstance(payload, dict):
396
+ if not getattr(args, "text", False) or not isinstance(payload, dict):
397
397
  return payload
398
398
  credentials = [c for c in payload.get("credentials") or [] if isinstance(c, dict)]
399
399
  default = payload.get("default")
@@ -6,8 +6,8 @@ agreed those declarations may reach. A server here carries the credential it is
6
6
  with, and the allow-list of tools on it a deploy is permitted to name.
7
7
 
8
8
  cmpnd tool-servers create --url https://mcp.exa.ai/mcp --credential exa-prod
9
- cmpnd tool-servers list
10
- cmpnd tool-servers show <server_id>
9
+ cmpnd tool-servers list --text
10
+ cmpnd tool-servers show <server_id> --text
11
11
  cmpnd tool-servers allow <server_id> web_search_exa
12
12
  cmpnd tool-servers deny <server_id> --all
13
13
  cmpnd tool-servers refresh <server_id>
@@ -48,7 +48,7 @@ import json
48
48
  from argparse import ArgumentParser, _SubParsersAction
49
49
  from typing import Any
50
50
 
51
- from .. import api_client
51
+ from .. import api_client, views
52
52
  from . import provider_credentials
53
53
 
54
54
  _ROOT = "/api/v1/org/tool-servers"
@@ -66,7 +66,7 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
66
66
  create.set_defaults(func=handle_create)
67
67
 
68
68
  listing = sub.add_parser("list", help="Show the tool servers your org has registered")
69
- listing.add_argument("--json", action="store_true", help="Emit the raw JSON instead of the rendering")
69
+ views.add_text_flag(listing)
70
70
  listing.set_defaults(func=handle_list)
71
71
 
72
72
  show = sub.add_parser("show", help="Show one server, its credential, and its tools")
@@ -74,9 +74,9 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
74
74
  show.add_argument(
75
75
  "--schemas",
76
76
  action="store_true",
77
- help="Also print each tool's reduced argument schema — the shape the platform will enforce",
77
+ help="With --text, also print each tool's reduced argument schema — the shape the platform will enforce",
78
78
  )
79
- show.add_argument("--json", action="store_true", help="Emit the raw JSON instead of the rendering")
79
+ views.add_text_flag(show)
80
80
  show.set_defaults(func=handle_show)
81
81
 
82
82
  for verb, effect in (
@@ -232,7 +232,7 @@ def handle_create(client: api_client.ApiClient, args: Any) -> Any:
232
232
 
233
233
  def handle_list(client: api_client.ApiClient, args: Any) -> Any:
234
234
  payload = client.get(_ROOT)
235
- if getattr(args, "json", False):
235
+ if not getattr(args, "text", False):
236
236
  return payload
237
237
  servers = _servers(payload)
238
238
  if not servers:
@@ -246,13 +246,13 @@ def handle_list(client: api_client.ApiClient, args: Any) -> Any:
246
246
  f"{str(server.get('id', '')).ljust(14)} {str(server.get('name') or '').ljust(16)} "
247
247
  f"{server.get('url', '')} [{server.get('credential_name') or 'no credential'}]"
248
248
  )
249
- print("Read one server's tools and its allow-list with `cmpnd tool-servers show <server_id>`.")
249
+ print("Read one server's tools and its allow-list with `cmpnd tool-servers show <server_id> --text`.")
250
250
  return None
251
251
 
252
252
 
253
253
  def handle_show(client: api_client.ApiClient, args: Any) -> Any:
254
254
  server = client.get(f"{_ROOT}/{args.server_id}")
255
- if getattr(args, "json", False):
255
+ if not getattr(args, "text", False):
256
256
  return server
257
257
  _render_server(server if isinstance(server, dict) else {}, schemas=getattr(args, "schemas", False))
258
258
  return None
@@ -283,7 +283,7 @@ def _grant(client: api_client.ApiClient, args: Any, verb: str) -> Any:
283
283
  if not getattr(args, "all", False) and not tools:
284
284
  raise SystemExit(
285
285
  f"`tool-servers {verb}` needs at least one tool name, or --all. Run "
286
- f"`cmpnd tool-servers show {args.server_id}` to see what this server lists."
286
+ f"`cmpnd tool-servers show {args.server_id} --text` to see what this server lists."
287
287
  )
288
288
  body: dict[str, Any] = {"all": True} if getattr(args, "all", False) else {"tools": tools}
289
289
  server = client.post(f"{_ROOT}/{args.server_id}/{verb}", json=body)
@@ -1301,10 +1301,22 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
1301
1301
  def _handler(name: str) -> Any:
1302
1302
  return verbs.by_name(name).handler
1303
1303
 
1304
+ # A verb that repeats a namespaced command says so first, from its VERBS
1305
+ # row, so `cmpnd -h` tells a shortcut from a separate feature.
1306
+ def _help(name: str, text: str = "") -> str:
1307
+ shortcut_for = verbs.by_name(name).shortcut_for
1308
+ if not shortcut_for:
1309
+ return text
1310
+ prefix = f"Shortcut for `cmpnd {shortcut_for}`"
1311
+ return f"{prefix}; {text}" if text else prefix
1312
+
1304
1313
  ps = subparsers.add_parser(
1305
1314
  "ps",
1306
- help="List deployments (Docker-style)",
1307
- description="List deployments belonging to the calling org, newest first.",
1315
+ help=_help("ps", "renders a table"),
1316
+ description=(
1317
+ "List deployments belonging to the calling org, newest first. Shortcut for "
1318
+ "`cmpnd deployments list` that renders a table; --json prints the same response."
1319
+ ),
1308
1320
  epilog="Examples:\n cmpnd ps\n cmpnd ps --status ready --json\n",
1309
1321
  formatter_class=raw,
1310
1322
  )
@@ -1352,8 +1364,11 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
1352
1364
 
1353
1365
  insp = subparsers.add_parser(
1354
1366
  "inspect",
1355
- help="Full JSON for a deployment",
1356
- description="Print the full deployment record as JSON. Equivalent to `cmpnd status <id> --json`.",
1367
+ help=_help("inspect", "--source prints the stored program"),
1368
+ description=(
1369
+ "Print the full deployment record as JSON, as `cmpnd deployments show` does. "
1370
+ "--source prints the deployment's stored program file instead."
1371
+ ),
1357
1372
  formatter_class=raw,
1358
1373
  )
1359
1374
  insp.add_argument("id")
@@ -1396,8 +1411,11 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
1396
1411
 
1397
1412
  rn = subparsers.add_parser(
1398
1413
  "run",
1399
- help="Run a deployment with a JSON input body",
1400
- description="Submit one durable run to a ready deployment and wait for its result.",
1414
+ help=_help("run"),
1415
+ description=(
1416
+ "Submit one durable run to a ready deployment and wait for its result. "
1417
+ "Shortcut for `cmpnd deployments run`."
1418
+ ),
1401
1419
  epilog=(
1402
1420
  "Examples:\n"
1403
1421
  ' cmpnd run d_a1b2c3d4 \'{"question": "what is dspy?"}\'\n'
@@ -41,7 +41,9 @@ class Verb:
41
41
  ``deploy(path)``); ``"entity"`` binds it as a method on
42
42
  ``shell_entity`` (e.g. ``deps.d_xxx.status()``). ``shell_method``
43
43
  defaults to ``name`` and gives the registry a single hook to rename
44
- a method without the hint helpers going stale.
44
+ a method without the hint helpers going stale. ``shortcut_for`` names the
45
+ namespaced command a verb repeats, such as ``"deployments list"`` for
46
+ ``ps``. Its CLI help starts with "Shortcut for `cmpnd deployments list`".
45
47
  """
46
48
 
47
49
  name: str
@@ -49,6 +51,7 @@ class Verb:
49
51
  shell_kind: Literal["top_level", "entity"]
50
52
  shell_entity: str | None = None
51
53
  shell_method: str | None = None
54
+ shortcut_for: str | None = None
52
55
 
53
56
  def __post_init__(self) -> None:
54
57
  if self.shell_kind == "entity" and not self.shell_entity:
@@ -65,13 +68,13 @@ class Verb:
65
68
  # functions (`_shell_method`, `register`), never at module scope.
66
69
  # Module-scope binding also makes the table trivially inspectable.
67
70
  _VERBS: tuple["Verb", ...] = (
68
- Verb("ps", commands.top.cmd_ps, "top_level"),
71
+ Verb("ps", commands.top.cmd_ps, "top_level", shortcut_for="deployments list"),
69
72
  Verb("deploy", commands.top.cmd_deploy, "top_level"),
70
73
  Verb("optimize", commands.top.cmd_optimize, "top_level"),
71
74
  Verb("status", commands.top.cmd_status, "entity", "Deployment"),
72
75
  Verb("logs", commands.top.cmd_logs, "entity", "Deployment"),
73
- Verb("inspect", commands.top.cmd_inspect, "entity", "Deployment"),
74
- Verb("run", commands.top.cmd_run, "entity", "Deployment"),
76
+ Verb("inspect", commands.top.cmd_inspect, "entity", "Deployment", shortcut_for="deployments show"),
77
+ Verb("run", commands.top.cmd_run, "entity", "Deployment", shortcut_for="deployments run"),
75
78
  Verb("schema", commands.top.cmd_schema, "entity", "Deployment"),
76
79
  Verb("sample", commands.top.cmd_sample, "entity", "Deployment"),
77
80
  )
@@ -164,6 +167,7 @@ DOMAIN_VERBS: dict[str, str] = {
164
167
  "trash": "moves a program to the Trash, where it stays restorable, and delete would read as the permanent purge",
165
168
  "restore": "returns a program from the Trash with its history, which create would not",
166
169
  "purge": "deletes a program in the Trash for good, the irreversible step after trash",
170
+ "rename": "gives a program a new current name and keeps the old one resolving to it, which update would hide",
167
171
  }
168
172
 
169
173
  #: Leaves naming a related collection or sub-record rather than an action.
@@ -0,0 +1,25 @@
1
+ """The output rule for namespaced commands.
2
+
3
+ A namespaced read, such as `cmpnd traces show` or `cmpnd tool-servers list`, prints
4
+ the platform's JSON by default, and a human view is an opt-in flag: `--tree` and
5
+ `--timeline` on `traces show`, `--text` on the reads below. An action command may
6
+ print a short result instead and take `--json` for the whole answer, as
7
+ `cmpnd programs create` prints the id. The top-level commands (`cmpnd ps`,
8
+ `cmpnd status`) are the human loop: they render text and take `--json`.
9
+ `tests/test_cli/test_parity.py` refuses a namespaced read that offers `--json`.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import argparse
15
+
16
+
17
+ def add_text_flag(parser: argparse.ArgumentParser) -> None:
18
+ """Give a namespaced read the opt-in `--text` view.
19
+
20
+ Some reads rendered text by default and took `--json` before the CLI settled on
21
+ the rule, so `--json` stays accepted and hidden, and a script that passes it
22
+ keeps working.
23
+ """
24
+ parser.add_argument("--text", action="store_true", help="Render for a person instead of printing JSON")
25
+ parser.add_argument("--json", action="store_true", help=argparse.SUPPRESS)
@@ -836,6 +836,47 @@ class Client:
836
836
 
837
837
  return optimization.list_candidates(run_id, cfg=self._config)
838
838
 
839
+ def list_deployments(
840
+ self, *, status: str | None = None, since: str | None = None, limit: int = 50, offset: int = 0
841
+ ) -> list[dict[str, Any]]:
842
+ """The organization's deployments, newest first.
843
+
844
+ Returns the list itself, not the response envelope. ``status`` is one of
845
+ ``pending``, ``parsing``, ``optimizing``, ``ready`` or ``failed``, and
846
+ ``since`` is an ISO 8601 timestamp. ``offset`` must be a whole multiple of
847
+ ``limit``, because the route pages by page number. ``limit`` must not
848
+ exceed 500, the most deployments the route returns per page.
849
+ """
850
+ self._check_active()
851
+ page = _deployments.list_deployments(
852
+ status=status,
853
+ since=since,
854
+ limit=limit,
855
+ offset=offset,
856
+ api_key=self._config.api_key,
857
+ endpoint=self._config.endpoint,
858
+ )
859
+ return page.get("deployments", [])
860
+
861
+ def get_deployment(self, deployment_id: str) -> dict[str, Any]:
862
+ """Fetch one deployment's record: its status, program, model and metadata."""
863
+ self._check_active()
864
+ return _deployments.get_deployment(deployment_id, api_key=self._config.api_key, endpoint=self._config.endpoint)
865
+
866
+ def get_deployment_source(self, deployment_id: str, path: str | None = None) -> str:
867
+ """Read the program source a deployment stores, as text.
868
+
869
+ Without ``path`` it returns the program file the deployment runs. A
870
+ continuation's deployment holds the chosen candidate's program, so this
871
+ reads what the continuation runs. ``path`` names another archive-relative
872
+ file of the stored bundle. The file decodes with the encoding its PEP 263
873
+ coding comment declares, and with UTF-8 when it declares none.
874
+ """
875
+ self._check_active()
876
+ return _deployments.get_source(
877
+ deployment_id, path=path, api_key=self._config.api_key, endpoint=self._config.endpoint
878
+ )
879
+
839
880
  def get_deployment_signature(self, deployment_id: str) -> DeploymentSignatureResponse:
840
881
  """Fetch one deployment's persisted artifact metadata."""
841
882
  self._check_active()
@@ -345,7 +345,7 @@ def _resolve_mcp_tool_references(client: httpx.Client, config, references: list[
345
345
  f"your organization's registry holds no tool named {reference.tool_name!r} on "
346
346
  f"{reference.server_url}, so this deploy cannot pin the schema its calls would be "
347
347
  "validated against. Read what the registry does hold with "
348
- f"`cmpnd tool-servers show {server_id}`, and if the server has grown the tool since it "
348
+ f"`cmpnd tool-servers show {server_id} --text`, and if the server has grown the tool since it "
349
349
  f"was registered, `cmpnd tool-servers refresh {server_id}` re-reads its listing."
350
350
  )
351
351
  pinned[(reference.server_url, reference.tool_name)] = mcp_servers.PinnedTool(
@@ -99,6 +99,24 @@ also names the `cmpnd programs optimized` command for a compiled program hash.
99
99
  program hash, the value in the `program_hash` column of
100
100
  `cmpnd programs optimized list`, as `cmpnd programs select` does.
101
101
 
102
+ ## Renaming a program
103
+
104
+ `cmpnd programs rename PROGRAM NAME` makes NAME the current name of PROGRAM,
105
+ which is a program name or a `p_` id. The program keeps its id and its
106
+ history. The CLI checks NAME's syntax before it sends anything, looks a
107
+ PROGRAM name up as the other `cmpnd programs` commands do, and sends
108
+ `POST /api/v1/programs/{id}/rename`. The command needs `traces:write` or
109
+ `optimizations:write`.
110
+
111
+ The old name keeps resolving to the program, so code that still declares it
112
+ reaches the same program. A program with no name takes its first name this
113
+ way, and code that declares the new name with `cmpnd.Program(name, ...)`
114
+ traces to it. Serve refuses a name another live
115
+ program answers to, as its current or a retired name. A program in the Trash
116
+ is refused until `cmpnd programs restore` returns it. A server from before the
117
+ rename route says so, and the error points at the program's page in the web
118
+ app, which renames it too.
119
+
102
120
  ## The Trash
103
121
 
104
122
  A program in the Trash leaves every view, and its traces with it, until it is
@@ -154,11 +172,28 @@ release without the warning, set `CMPND_NO_UPGRADE_WARNING=1`. In code,
154
172
  `warnings.filterwarnings("ignore", category=cmpnd.UpgradeRequiredWarning)`
155
173
  does the same.
156
174
 
175
+ ## Output of namespaced and top-level commands
176
+
177
+ A namespaced read, such as `cmpnd traces show`, `cmpnd deployments list` or
178
+ `cmpnd tool-servers list`, prints the API's JSON by default, so a script can
179
+ pipe it to `jq`. A human view is an opt-in flag: `--tree` and `--timeline` on
180
+ `traces show`, and `--text` on `tool-servers list`, `tool-servers show` and
181
+ `credentials list`. Those three accept `--json` as well, so older scripts keep
182
+ working. An action command may print a short result and take `--json` for the
183
+ whole answer: `cmpnd programs create` prints the new id, and
184
+ `cmpnd optimizations continue` prints the best deployment. The top-level
185
+ commands below are the human loop: they render text and take `--json`.
186
+ `cmpnd/cli/views.py` states the rule, and `tests/test_cli/test_parity.py`
187
+ refuses a namespaced read that offers `--json`.
188
+
157
189
  ## Deploy flow (Docker-style)
158
190
 
159
191
  These commands print human-readable output by default. Each takes `--json` for
160
192
  a stable, scriptable shape. A deployment ID may be any unambiguous prefix,
161
- such as `d_a1b2c3d4`.
193
+ such as `d_a1b2c3d4`. Three of them are shortcuts, and their help says so:
194
+ `cmpnd ps` repeats `cmpnd deployments list`, `cmpnd run` repeats
195
+ `cmpnd deployments run`, and `cmpnd inspect` repeats `cmpnd deployments show`.
196
+ `Verb.shortcut_for` in `cmpnd/cli/verbs.py` declares each one.
162
197
 
163
198
  - `cmpnd deploy <source.py|-> PROGRAM_NAME [--entrypoint ATTRIBUTE]
164
199
  [--source-root DIR] [--include PATH ...] [--run <json>] [--metadata <json>]`
@@ -560,10 +595,10 @@ cmpnd credentials create --name luna-exec --preset lunaroute < key.txt
560
595
  op read 'op://vault/openai/key' | cmpnd credentials create --name openai --preset openai
561
596
  ```
562
597
 
563
- `cmpnd credentials list` shows each credential's protocols, whether its host
564
- implies them, its address and the org's default. A member sees the scheme and
565
- host of the address, and an owner sees the whole of it. `--json` prints the
566
- listing as the API returns it.
598
+ `cmpnd credentials list` prints the listing as the API returns it: each
599
+ credential's protocols, whether its host implies them, its address and the
600
+ org's default. `--text` renders it for a person. A member sees the scheme and
601
+ host of the address, and an owner sees the whole of it.
567
602
 
568
603
  `cmpnd credentials protocols NAME` shows a credential's protocols. `--add` and
569
604
  `--remove` start from them, whether stated or implied by the host, and `--set`
@@ -620,18 +655,19 @@ server, the credential it uses and the allow-list of tools a deploy may name.
620
655
 
621
656
  ```bash
622
657
  cmpnd tool-servers create --url https://mcp.exa.ai/mcp --credential exa-prod [--name exa]
623
- cmpnd tool-servers list
624
- cmpnd tool-servers show <server_id> [--schemas]
658
+ cmpnd tool-servers list [--text]
659
+ cmpnd tool-servers show <server_id> [--text [--schemas]]
625
660
  cmpnd tool-servers refresh <server_id>
626
661
  cmpnd tool-servers delete <server_id> --force
627
662
  ```
628
663
 
629
664
  `create` registers the server and has the platform list its tools. The
630
665
  platform contacts the server, and the CLI never does. `refresh` lists the
631
- tools again after a vendor changes them. `show` prints each tool with its
632
- allow-list state and a one-line description. `--schemas` adds the reduced
633
- argument schema the platform enforces. Every command takes `--json` for the
634
- raw payload.
666
+ tools again after a vendor changes them. `list` and `show` print the API's
667
+ JSON. With `--text`, `show` prints each tool with its allow-list state and a
668
+ one-line description, and `--schemas` adds the reduced argument schema the
669
+ platform enforces. `create`, `allow`, `deny` and `refresh` render the server
670
+ as it now stands, and `--json` prints the raw payload instead.
635
671
 
636
672
  When the platform cannot list a server's tools because of the server itself,
637
673
  `create` and `refresh` fail with a `424` that names the URL, the credential and
@@ -881,7 +917,7 @@ creator after the creator leaves. The customer then:
881
917
  same name, and `cmpnd credentials create --kind mcp --server URL
882
918
  --name NAME` with the same server and name, replace the sealed keys in
883
919
  place. The tool server and the deployment keep pointing at them.
884
- 3. Runs `cmpnd tool-servers show SERVER_ID` and
920
+ 3. Runs `cmpnd tool-servers show SERVER_ID --text` and
885
921
  `cmpnd tool-servers refresh SERVER_ID` to read the tools and allow-list
886
922
  under the new key.
887
923
  4. Runs `cmpnd ps`, `cmpnd sample ID` and `cmpnd run ID '<json>'`. The
@@ -211,8 +211,13 @@ methods:
211
211
 
212
212
  - Traces: `sdk.list_traces(**filters)` and `sdk.get_trace(trace_id)`. The
213
213
  `program=` filter takes a program name or a `p_` id.
214
- - Deployments: `sdk.get_deployment_signature(deployment_id)` returns the
215
- selected artifact's typed metadata. It reads no worker status or executions.
214
+ - Deployments: `sdk.list_deployments(status=..., since=..., limit=...,
215
+ offset=...)` lists the organization's deployments, newest first.
216
+ `sdk.get_deployment(deployment_id)` returns one deployment's record.
217
+ `sdk.get_deployment_source(deployment_id, path=None)` returns the program
218
+ file the deployment stores, or the archive-relative file `path` names.
219
+ `sdk.get_deployment_signature(deployment_id)` returns the selected
220
+ artifact's typed metadata. It reads no worker status or executions.
216
221
  - Assessments, in development behind `CMPND_CLI_DEV=1`:
217
222
  `sdk.create_assessment(trace_id, conclusion=..., body=...,
218
223
  annotations=...)`, `sdk.list_assessments(program=... | trace_id=...,