bantamkit 0.29.2__tar.gz → 0.31.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 (217) hide show
  1. {bantamkit-0.29.2 → bantamkit-0.31.0}/PKG-INFO +2 -2
  2. bantamkit-0.31.0/_assets/pricing/default.json +7 -0
  3. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/schemas/shiftwork-checkpoint.json +12 -1
  4. bantamkit-0.31.0/_assets/tools/memory_dream.json +20 -0
  5. bantamkit-0.31.0/_assets/tools/repo_map.json +44 -0
  6. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/tools/shiftwork_clock_out.json +1 -1
  7. bantamkit-0.31.0/_assets/tools/token_ledger.json +40 -0
  8. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/__init__.py +1 -1
  9. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/eventlog.py +6 -4
  10. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/mcpserver.py +742 -17
  11. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/memory/__init__.py +17 -1
  12. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/memory/__main__.py +1 -1
  13. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/memory/component.py +206 -4
  14. bantamkit-0.31.0/src/bantamkit/memory/dream.py +751 -0
  15. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/memory/store.py +158 -4
  16. bantamkit-0.31.0/src/bantamkit/pricing.py +411 -0
  17. bantamkit-0.31.0/src/bantamkit/repomap.py +1026 -0
  18. bantamkit-0.31.0/src/bantamkit/selfupdate.py +456 -0
  19. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/shiftwork.py +63 -1
  20. bantamkit-0.31.0/src/bantamkit/tokenledger.py +468 -0
  21. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/data/served-tool-surface.json +106 -2
  22. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_amendguard.py +34 -0
  23. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_bantamkit_read_tool.py +3 -0
  24. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_build_identity.py +30 -0
  25. bantamkit-0.31.0/tests/test_conformance_harness_resilience.py +206 -0
  26. bantamkit-0.31.0/tests/test_conformance_suite_table_gate.py +124 -0
  27. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_eventlog.py +6 -2
  28. bantamkit-0.31.0/tests/test_install_shape.py +653 -0
  29. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_mcpserver.py +284 -5
  30. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_memory.py +259 -0
  31. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_memory_compact_tool.py +4 -1
  32. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_memory_component.py +72 -1
  33. bantamkit-0.31.0/tests/test_memory_dream.py +875 -0
  34. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_platform_assumption_gate.py +80 -3
  35. bantamkit-0.31.0/tests/test_pricing.py +462 -0
  36. bantamkit-0.31.0/tests/test_repo_map_tool.py +297 -0
  37. bantamkit-0.31.0/tests/test_repomap.py +649 -0
  38. bantamkit-0.31.0/tests/test_selfupdate.py +717 -0
  39. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_served_tool_count_records.py +110 -14
  40. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_shiftwork.py +285 -0
  41. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_skillaudit.py +6 -1
  42. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_status_surface.py +149 -2
  43. bantamkit-0.31.0/tests/test_tokenledger.py +614 -0
  44. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_tool_manifest.py +3 -0
  45. {bantamkit-0.29.2 → bantamkit-0.31.0}/.gitignore +0 -0
  46. {bantamkit-0.29.2 → bantamkit-0.31.0}/README.md +0 -0
  47. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/contracts/default.yaml +0 -0
  48. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/manifest.yaml +0 -0
  49. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/repo/HISTORY.md +0 -0
  50. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/repo/README.md +0 -0
  51. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/repo/docs/architecture.md +0 -0
  52. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/repo/docs/runbook.md +0 -0
  53. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/repo/issues/142-settlement-timeout.md +0 -0
  54. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/repo/patches/0009-retry-budget.patch +0 -0
  55. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/repo/src/ledger/__init__.py +0 -0
  56. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/repo/src/ledger/config.py +0 -0
  57. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/repo/src/ledger/errors.py +0 -0
  58. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/repo/src/ledger/posting.py +0 -0
  59. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/repo/src/ledger/registry.py +0 -0
  60. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/repo/src/ledger/report.py +0 -0
  61. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/repo/src/ledger/retry.py +0 -0
  62. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/repo/src/ledger/settle.py +0 -0
  63. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/repo/src/ledger/validate.py +0 -0
  64. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/repo/tests/test_posting.py +0 -0
  65. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/repo/tests/test_settle.py +0 -0
  66. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/tasks/dt-error-contract.yaml +0 -0
  67. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/tasks/dt-handler-map.yaml +0 -0
  68. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/tasks/dt-patch-before-after.yaml +0 -0
  69. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/tasks/dt-retry-attempts.yaml +0 -0
  70. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/tasks/dt-settlement-config.yaml +0 -0
  71. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/tasks/dt-symbol-home.yaml +0 -0
  72. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/tasks/dt-trace-blame.yaml +0 -0
  73. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/devteam/tasks/dt-unread-key.yaml +0 -0
  74. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/document/tasks/doc-large-in-137.yaml +0 -0
  75. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/document/tasks/doc-large-in-359.yaml +0 -0
  76. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/document/tasks/doc-large-in-372.yaml +0 -0
  77. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/document/tasks/doc-large-out-11764.yaml +0 -0
  78. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/document/tasks/doc-large-out-4137.yaml +0 -0
  79. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/document/tasks/doc-large-out-8022.yaml +0 -0
  80. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/document/tasks/doc-small-137.yaml +0 -0
  81. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/document/tasks/doc-small-261.yaml +0 -0
  82. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/document/tasks/doc-small-388.yaml +0 -0
  83. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/fixtures/.gitkeep +0 -0
  84. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/fixtures/catalog.json +0 -0
  85. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/perturbations/task-completion.yaml +0 -0
  86. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/tasks/.gitkeep +0 -0
  87. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/tasks/extract-contact.yaml +0 -0
  88. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/tasks/extract-invoice.yaml +0 -0
  89. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/tasks/extract-order.yaml +0 -0
  90. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/tasks/extract-schedule.yaml +0 -0
  91. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/tasks/extract-versions.yaml +0 -0
  92. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/tasks/nav-prod-port.yaml +0 -0
  93. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/tasks/nav-release-bundle.yaml +0 -0
  94. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/tasks/recall-audit-retention.yaml +0 -0
  95. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/tasks/recall-cache-ttl.yaml +0 -0
  96. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/tasks/recall-db-port.yaml +0 -0
  97. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/tasks/recall-deploy.yaml +0 -0
  98. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/tasks/recall-env-endpoint.yaml +0 -0
  99. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/tasks/recall-oncall-rotation.yaml +0 -0
  100. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/tasks/recall-oncall.yaml +0 -0
  101. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/tasks/recall-org-quota.yaml +0 -0
  102. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/tasks/recall-owner.yaml +0 -0
  103. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/tasks/shop-basket-total.yaml +0 -0
  104. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/tasks/shop-cheapest.yaml +0 -0
  105. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/tasks/shop-compare.yaml +0 -0
  106. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/tasks/shop-gadget-value.yaml +0 -0
  107. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/tasks/shop-stock-total.yaml +0 -0
  108. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/evals/tasks/shop-total.yaml +0 -0
  109. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/profiles/default.yaml +0 -0
  110. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/profiles/patient.yaml +0 -0
  111. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/rubrics/.gitkeep +0 -0
  112. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/rubrics/code-quality.yaml +0 -0
  113. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/rubrics/grounded-completion.yaml +0 -0
  114. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/rubrics/task-completion.yaml +0 -0
  115. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/skills/.gitkeep +0 -0
  116. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/skills/file-graph.md +0 -0
  117. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/skills/memory.md +0 -0
  118. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/tools/.gitkeep +0 -0
  119. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/tools/bantamkit_read.json +0 -0
  120. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/tools/bantamkit_status.json +0 -0
  121. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/tools/build_identity.json +0 -0
  122. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/tools/document_list.json +0 -0
  123. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/tools/document_read.json +0 -0
  124. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/tools/file_graph.json +0 -0
  125. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/tools/memory_compact.json +0 -0
  126. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/tools/memory_recall.json +0 -0
  127. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/tools/memory_save.json +0 -0
  128. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/tools/shiftwork_clock_in.json +0 -0
  129. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/tools/shiftwork_status.json +0 -0
  130. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/tools/skill_audit.json +0 -0
  131. {bantamkit-0.29.2 → bantamkit-0.31.0}/_assets/tools/validate_json.json +0 -0
  132. {bantamkit-0.29.2 → bantamkit-0.31.0}/hatch_build.py +0 -0
  133. {bantamkit-0.29.2 → bantamkit-0.31.0}/pyproject.toml +0 -0
  134. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/agent.py +0 -0
  135. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/assets.py +0 -0
  136. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/budget.py +0 -0
  137. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/client.py +0 -0
  138. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/contract.py +0 -0
  139. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/criticreplay.py +0 -0
  140. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/critique.py +0 -0
  141. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/docmanifest.py +0 -0
  142. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/docread.py +0 -0
  143. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/evalrun.py +0 -0
  144. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/filegraph.py +0 -0
  145. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/hostinstall.py +0 -0
  146. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/loopguard.py +0 -0
  147. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/mcpreport.py +0 -0
  148. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/memory/divergence.py +0 -0
  149. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/memory/layers.py +0 -0
  150. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/pdfread.py +0 -0
  151. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/profile.py +0 -0
  152. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/skillaudit.py +0 -0
  153. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/statusline.py +0 -0
  154. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/structured.py +0 -0
  155. {bantamkit-0.29.2 → bantamkit-0.31.0}/src/bantamkit/textutil.py +0 -0
  156. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/cli_exit_status_probe.py +0 -0
  157. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/conftest.py +0 -0
  158. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/data/docread/bad-crc.docx +0 -0
  159. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/data/docread/charref-4301-digits.html +0 -0
  160. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/data/docread/charset-table.json +0 -0
  161. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/data/docread/compression-method-9.docx +0 -0
  162. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/data/docread/corrupt-deflate.docx +0 -0
  163. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/data/docread/encrypted-member.docx +0 -0
  164. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/data/docread/encrypted-mimetype.odt +0 -0
  165. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/data/docread/eszett-cell-ref.xlsx +0 -0
  166. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/data/docread/internal-dtd-entity.docx +0 -0
  167. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/data/docread/rfc2231-charset.eml +0 -0
  168. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/data/docread/rfc822-nested-twice.eml +0 -0
  169. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/data/docread/unicode-digit-shared-string.xlsx +0 -0
  170. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/data/docread/x-uuencode.eml +0 -0
  171. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/data/f8404ab-perturbation-baseline.json +0 -0
  172. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/data/platform-assumption-baseline.json +0 -0
  173. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/docread_fixtures.py +0 -0
  174. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/perturbation_baseline_harness.py +0 -0
  175. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/rbp16_effect_probe.py +0 -0
  176. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/rbp18_payload_probe.py +0 -0
  177. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_adapter.py +0 -0
  178. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_agent.py +0 -0
  179. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_budget.py +0 -0
  180. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_client.py +0 -0
  181. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_compaction_corpus_survey.py +0 -0
  182. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_conformance.py +0 -0
  183. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_contract_fanout.py +0 -0
  184. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_criticreplay.py +0 -0
  185. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_critique.py +0 -0
  186. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_doc_commands_gate.py +0 -0
  187. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_docread.py +0 -0
  188. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_docread_ceilings.py +0 -0
  189. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_document_manifest_parity.py +0 -0
  190. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_document_setup.py +0 -0
  191. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_document_tasks.py +0 -0
  192. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_document_tools.py +0 -0
  193. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_encoding_gate.py +0 -0
  194. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_evalrun.py +0 -0
  195. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_field_program_gates.py +0 -0
  196. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_field_programs.py +0 -0
  197. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_filegraph.py +0 -0
  198. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_hostinstall.py +0 -0
  199. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_ladder_statistics.py +0 -0
  200. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_launcher_which.py +0 -0
  201. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_layers.py +0 -0
  202. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_loopguard.py +0 -0
  203. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_mcp_endpoint.py +0 -0
  204. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_mcpdrift.py +0 -0
  205. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_mcpreport.py +0 -0
  206. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_memory_divergence.py +0 -0
  207. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_memory_layers.py +0 -0
  208. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_memory_store_tripwire.py +0 -0
  209. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_mutmatrix.py +0 -0
  210. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_newline_gate.py +0 -0
  211. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_packaging.py +0 -0
  212. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_pdfread.py +0 -0
  213. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_pinharness_ledger.py +0 -0
  214. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_statusline.py +0 -0
  215. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_structured.py +0 -0
  216. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_thread_exception_gate.py +0 -0
  217. {bantamkit-0.29.2 → bantamkit-0.31.0}/tests/test_version_agreement.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: bantamkit
3
- Version: 0.29.2
3
+ Version: 0.31.0
4
4
  Summary: bantamweight tooling — harness primitives that lift small-model agents
5
5
  License-Expression: MIT
6
6
  Requires-Python: >=3.11
@@ -0,0 +1,7 @@
1
+ {
2
+ "schema_version": 1,
3
+ "currency": "USD",
4
+ "unit": "micro_usd_per_million_tokens",
5
+ "note": "Ships with NO rates, deliberately. bantamkit is offline and nothing in this repository or on the machine it was built on carries a published price, so every rate here would have had to be recalled rather than sourced - which is the unfalsifiable figure this project exists to refuse. The mechanism is complete and the refusal path is therefore the DEFAULT: price_tokens answers {\"unavailable\": ...} for every model until an operator records a rate. To record one, copy this file, add an entry under 'rates', and point BANTAMKIT_PRICES at the copy. Each entry needs 'recorded' (YYYY-MM-DD, the day YOU read the rate), 'source' (where you read it, so the next reader can re-derive it), and one or more of the four token classes priced in micro-USD per 1,000,000 tokens - so $3.00 per million input tokens is 3000000. The loader REFUSES a rate that has no date or no source: a number in this file without both is not a fact.",
6
+ "rates": {}
7
+ }
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://bantamkit.dev/schemas/shiftwork-checkpoint.json",
4
4
  "title": "Shift-work checkpoint contract v1",
5
- "$comment": "Encodes checkpoint contract v1 (docs/superpowers/specs/2026-08-10-shift-work-checkpoint-contract-draft.md) plus the two driver-forced deltas: plan.units[].role (model dispatch without reading briefs) and state.external[].until_cmd (machine-checkable wait, replacing prose `until`). Re-planning needs no schema change: a planner unit is just a unit. STRICTNESS POSTURE: `version` is const-pinned to 1 so a reader can refuse unknown majors; every object the driver or a session reads by field name sets additionalProperties:false, and every field the draft's schema block shows on every instance is required (empty arrays are legal, so a fresh checkpoint is cheap to write). The two exceptions are `history[]` and `retro[]` items: those are the free-text annotation space the draft treats as notes, so they allow extra keys (e.g. a session adding `seq` or `tokens`) while still requiring their load-bearing fields. `units[].commits` is optional because the draft only carries it on completed units. `state.external[].status` is a non-empty string rather than an enum: the draft closes the enum for unit status (the driver's SUCCESS test) but never enumerates external status, and inventing values here would reject honest checkpoints. `plan.cursor` must name an existing unit id — JSON Schema cannot express that cross-reference, so the driver checks it structurally and escalates on a dangling cursor. Serialization: checkpoints are YAML for humans per the draft, but the v1 driver reads JSON only (stdlib-only rule), so sessions driven by driver.py write .json; this schema validates the parsed document either way.",
5
+ "$comment": "Encodes checkpoint contract v1 (docs/superpowers/specs/2026-08-10-shift-work-checkpoint-contract-draft.md) plus the two driver-forced deltas: plan.units[].role (model dispatch without reading briefs) and state.external[].until_cmd (machine-checkable wait, replacing prose `until`). Re-planning needs no schema change: a planner unit is just a unit. STRICTNESS POSTURE: `version` is const-pinned to 1 so a reader can refuse unknown majors; every object the driver or a session reads by field name sets additionalProperties:false, and every field the draft's schema block shows on every instance is required (empty arrays are legal, so a fresh checkpoint is cheap to write). The two exceptions are `history[]` and `retro[]` items: those are the free-text annotation space the draft treats as notes, so they allow extra keys (e.g. a session adding `seq` or `tokens`) while still requiring their load-bearing fields. `units[].commits` is optional because the draft only carries it on completed units. `state.external[].status` is a non-empty string rather than an enum: the draft closes the enum for unit status (the driver's SUCCESS test) but never enumerates external status, and inventing values here would reject honest checkpoints. `plan.cursor` must name an existing unit id — JSON Schema cannot express that cross-reference, so the driver checks it structurally and escalates on a dangling cursor. Serialization: checkpoints are YAML for humans per the draft, but the v1 driver reads JSON only (stdlib-only rule), so sessions driven by driver.py write .json; this schema validates the parsed document either way. AMENDMENT (job46/AS-2, docs/roadmap-agent-stack.md): `job.roles` is a THIRD v1 addition, beyond the two driver-forced deltas named above, and it is OPTIONAL — a checkpoint that omits it is exactly the document the rest of this comment describes, and every checkpoint written before it existed still validates unchanged. Both CLAUDE.md files say the model a unit runs on is `per role, never random, always logged`; logged it was, in `history[]`/`retro[]`, which are the two objects here that allow extra keys, so nothing could ever compare the model a role was ALLOWED to use against the model that answered. `job.roles` is that declaration, and it sits on `job` because that is where a reader already looks for the rules binding every unit. It is a MAP (unit role -> the model identifiers that role may report), not a record the driver reads by fixed field name, so the closure the rest of this file spells `additionalProperties: false` is spelled here as `propertyNames` over the SAME three names `plan.units[].role` enumerates, with `additionalProperties` carrying the value schema once instead of three times: a key outside the role enum is refused, and so is a value that is not a non-empty array of non-empty strings (an empty list would be a rule no session could satisfy, which is a typo and not a policy). A role the map does not name is unconstrained — declaring one role does not silently forbid the others. The ENFORCEMENT is not here: this file states the contract and the runtimes state the refusal, so no example error text appears in these descriptions. `version` stays 1 because nothing already in the document changes meaning: a reader that ignored `roles` would still read every other field correctly. What it would not do is enforce the rule — and since `job` is closed, an older reader does not ignore the key, it refuses the whole file. That refusal is the intended behaviour and not a gap: opening `job` so an old reader could skip the key is what would make this check bypassable by running an older bantamkit.",
6
6
  "type": "object",
7
7
  "required": ["version", "job", "plan", "state", "history", "retro", "handoff"],
8
8
  "additionalProperties": false,
@@ -27,6 +27,17 @@
27
27
  "type": "array",
28
28
  "items": {"type": "string", "minLength": 1},
29
29
  "description": "Invariants binding every unit, copied verbatim into each session."
30
+ },
31
+ "roles": {
32
+ "type": "object",
33
+ "description": "OPTIONAL. Per unit role, the model identifiers a session in that role may report. Omit it and the job behaves as it always has: the model is recorded and nothing compares it to anything. A role this map does not name is unconstrained; only a role named here is held to its list. Keys are the `plan.units[].role` enum, so a role that is not a role is refused rather than quietly ignored.",
34
+ "propertyNames": {"enum": ["planner", "implementer", "reviewer"]},
35
+ "additionalProperties": {
36
+ "type": "array",
37
+ "minItems": 1,
38
+ "items": {"type": "string", "minLength": 1},
39
+ "description": "The model identifiers this role may report, spelled exactly as a session logs them. Non-empty: a role allowed no model is a typo, not a policy."
40
+ }
30
41
  }
31
42
  }
32
43
  },
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "memory_dream",
3
+ "description": "Consolidate the memories the project layer and the machine-wide profile layer hold under the SAME NAME, and say exactly what changed. Byte-identical copies collapse to one; a pair that has diverged is UNIONED — every claim from both copies survives, never a winner-takes-all — and a relative date in a body is annotated with the day it resolves to against that fact's own mtime, never against today. The survivor stays in the writable project layer and the profile copy MOVES to that store's archive/: nothing is deleted and any consumed memory can be restored by name. This is a correctness pass, not a token saving: the profile index is derived at read time and is not loaded from a prompt, so consolidating it frees approximately no bytes — what it buys is one copy of a ruling instead of two that can disagree. It defaults to a DRY RUN because the profile store is machine-wide: a memory archived out of it stops answering for every other project on this machine that has no store of its own. Read the plan first, then call it again with dry_run false to apply it.",
4
+ "surfaces": ["mcp"],
5
+ "parameters": {
6
+ "type": "object",
7
+ "properties": {
8
+ "dry_run": {
9
+ "type": "boolean",
10
+ "description": "Preview only. True (the default) performs every read, merge and projection and writes nothing. Pass false to apply the plan."
11
+ }
12
+ }
13
+ },
14
+ "output_schema": {
15
+ "properties": { "result": { "title": "Result", "type": "string" } },
16
+ "required": ["result"],
17
+ "type": "object",
18
+ "title": "memory_dreamOutput"
19
+ }
20
+ }
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "repo_map",
3
+ "description": "A ranked map of a source tree: every file's definitions, ordered by how central that file is to the files you name in `focus`, truncated to a byte budget. Call it when you are about to work on a file and want to know which OTHER files matter to it — the ports, the callers, the module it reaches through a private helper — rather than reading a directory listing and guessing. `focus` is the file or files you are editing, relative to `root` and POSIX-separated; they are excluded from the listing because you already have them open, and an empty focus gives plain centrality over the whole tree. This is a PRECISION pass and it is not a token saving: the gate this feature was supposed to clear was refuted by measurement — discovery is 0.114% of real prompt tokens, because 97.8% of the bill is cache_read — so a map does not make a session cheaper. What it buys is the right file found sooner. Nothing the scanner cannot read is dropped silently: every unread file resolves into a named omission (unknown-language, unreadable-bytes, size-cap, no-definitions, unreachable, per-file-cap, budget) counted in a footer that is NOT charged to the budget. The budget is UTF-8 BYTES of the listing, not tokens; there is no model tokenizer in either runtime and this tool will not pretend to one.",
4
+ "surfaces": [
5
+ "mcp"
6
+ ],
7
+ "parameters": {
8
+ "type": "object",
9
+ "required": [
10
+ "root"
11
+ ],
12
+ "properties": {
13
+ "root": {
14
+ "type": "string",
15
+ "description": "Directory to map, absolute or relative to the server's working directory"
16
+ },
17
+ "focus": {
18
+ "type": "array",
19
+ "items": {
20
+ "type": "string"
21
+ },
22
+ "description": "The files you are working on, relative to `root` and POSIX-separated. They are excluded from the listing. A name that is not a scanned source is ignored rather than refused."
23
+ },
24
+ "budget": {
25
+ "type": "integer",
26
+ "minimum": 0,
27
+ "description": "UTF-8 bytes of listing to render; default 4000. The omission footer is not charged against it."
28
+ }
29
+ }
30
+ },
31
+ "output_schema": {
32
+ "properties": {
33
+ "result": {
34
+ "title": "Result",
35
+ "type": "string"
36
+ }
37
+ },
38
+ "required": [
39
+ "result"
40
+ ],
41
+ "type": "object",
42
+ "title": "repo_mapOutput"
43
+ }
44
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shiftwork_clock_out",
3
- "description": "Shift-work clock-out: record a finished unit — set its status, advance plan.cursor, merge handoff_patch, push history_entry onto the 5-entry ring — validating the whole mutated document against the checkpoint schema BEFORE an atomic write (a failure writes nothing and returns result=error). Every success appends one accounting line (unit, role, status, ts, plus your accounting fields, e.g. tokens/duration/model) to <checkpoint>.log.jsonl.",
3
+ "description": "Shift-work clock-out: record a finished unit — set its status, advance plan.cursor, merge handoff_patch, push history_entry onto the 5-entry ring — validating the whole mutated document against the checkpoint schema BEFORE an atomic write (a failure writes nothing and returns result=error). Every success appends one accounting line (unit, role, status, ts, plus your accounting fields, e.g. tokens/duration/model) to <checkpoint>.log.jsonl. If the checkpoint's job.roles names this unit's role, accounting.model must be one of that role's model identifiers, spelled exactly \u2014 a model that is not on the list, or none reported at all, is refused before anything is written; a role job.roles omits, and a checkpoint carrying no job.roles, are unconstrained.",
4
4
  "surfaces": [
5
5
  "mcp"
6
6
  ],
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "token_ledger",
3
+ "description": "What a session actually cost, read off the host's own transcripts. Walks `root` for `*.jsonl` transcripts -- the host writes `<cwd-slug>/<session>.jsonl` and `<cwd-slug>/<session>/subagents/*.jsonl` beneath a projects directory, which on this machine is `~/.claude/projects` -- and answers ONE JSON document: `root` (echoed as given), `transcripts` (files read), `lines` (records seen), `requests` (distinct API requests counted), `totals` (the four token classes), `sessions` (one row each), `omissions` (every line that was read and not counted), and `cost` only when `model` is given. This is the ONLY reader of the token counts: `docs/eventlog.md`'s four event streams record decisions, injections, tool calls and the host's arrival log, and NONE of the four carries a token count. Every figure here is the API's own `usage` block and nothing is estimated -- the byte-derived `est` figures in `tools/ledger/token-ledger.mjs` (tool_result bytes, repeated Reads) are deliberately NOT served, because an estimate handed to a model through a tool is an estimate that will be quoted back as a fact. COUNTING IS PER `requestId`, NEVER PER LINE: the host writes one API response as several assistant records -- a text block, a tool_use block -- which all carry the SAME `usage`, so summing records overcounts by the number of content blocks. The dedupe spans the WHOLE walk and not one file, because a resumed session rewrites earlier records verbatim into a new file and a per-file rule counts that request twice; the first occurrence in walk order wins and every later copy is reported as a `duplicate-request` omission rather than dropped in silence. EVERY LINE IS COUNTED OR OMITTED AND THE TWO ADD UP: `lines` equals `requests` plus the sum of every omission's `count`, always, so 'your transcripts hold no usage' is distinguishable from 'I skipped most of your transcripts'. An omission is `{subject, count, what}` with subject one of `undecodable-file`, `unparsed-line`, `not-an-object`, `no-session-id`, `not-an-assistant-record`, `no-usage`, `malformed-usage`, `no-request-id`, `duplicate-request`, and `what` naming the FIRST site as `<relpath>:<line>` plus `and N more` -- bounded on purpose, because a real corpus omits tens of thousands of lines as `not-an-assistant-record` (the host writes attachments, mode changes and titles into the same file) and listing them all would hand back a megabyte of paths in place of an answer. A blank line is not a record and is counted nowhere. A record is counted only when it carries a non-empty `sessionId`, `type` of `assistant`, a `message.usage` object holding ALL FOUR of `input_tokens`, `cache_creation_input_tokens`, `cache_read_input_tokens` and `output_tokens` as non-negative integers below 2**53, and a non-empty `requestId`; the host's other `usage` keys (`service_tier`, `iterations`, `server_tool_use`) are ignored, but a MISSING class is `malformed-usage` and never a zero, because a class defaulted to zero is a token invented. A session row carries `cwd` (the first one seen), `first` and `last` (the minimum and maximum timestamp, as strings), `requests`, `sidechain_requests` and the four classes. `sidechain_requests` is stated rather than hidden because it is an ASYMMETRY a caller would otherwise discover late: a subagent's transcript carries its PARENT's `sessionId` with `isSidechain: true`, so its cost lands in the parent session and is not a session of its own. Sessions are ordered by `first` as a STRING then by session id, both in code-point order, never by parsed time -- the host writes ISO-8601 with a `Z`, for which byte order already is time order. Directory listings are sorted by name in code-point order at every level, so the walk order -- which decides which copy of a duplicated `requestId` counts -- is a property of the tree and not of the filesystem. THERE IS NO TIME WINDOW, deliberately: the operator script has `--days N` and this has nothing, because a tool whose answer depends on the wall clock cannot be pinned by a gate that runs twice, and 'the last 7 days' is a question about a live machine rather than a fact about a corpus. `root` is the CALLER's, exactly as `skill_audit`'s is: this tool reads nothing but `root`, so it can be pointed at a frozen corpus and asked the same question twice. Pass `model` to convert the totals into money through the price table; `assets/pricing/default.json` ships with NO rates on purpose, so `{\"unavailable\": \"no rate recorded for model ...\"}` is the NORMAL answer and not an error path -- a rate enters only as an operator's own fact with its date and its source, through `$BANTAMKIT_PRICES` or through `prices`. `cost` carries `micros` (integer micro-USD), `amount` (a fixed-6-decimal string), a per-class `breakdown` and the `rate` that produced it; the four classes are priced separately because 98.1 % of a real prompt measured here was `cache_read`, and one averaged rate would be wrong in exactly that direction. Four argument failures are refused with their own sentences and never as a partial answer: an EMPTY `root` -- which passes JSON-schema `string` and would otherwise resolve to the server's own working directory -- a `root` that is missing, a `root` that is a file, and an EMPTY `model`, which would otherwise be reported as \"no rate recorded for model ''\" and read as a missing price rather than a missing argument. Nothing about the CONTENT of the tree refuses: a transcript that will not decode, a line that will not parse and a record with no usage are omissions and are counted, because a ledger that refused over one of eight hundred transcripts would have said nothing about the other seven hundred and ninety-nine. The one content failure that DOES refuse is a token total above 2**53-1, which is exact in Python and rounded in JavaScript: the place the two runtimes would part company is a refusal, not a wrong number. Deterministic: the tool reads `root`, and `prices` or `$BANTAMKIT_PRICES` when a `model` is named.",
4
+ "surfaces": [
5
+ "mcp"
6
+ ],
7
+ "parameters": {
8
+ "type": "object",
9
+ "required": [
10
+ "root"
11
+ ],
12
+ "properties": {
13
+ "root": {
14
+ "type": "string",
15
+ "description": "Directory of host transcripts to walk, absolute or relative to the server's working directory; `~/.claude/projects` is where the host keeps them on this machine. It must name a directory: the empty string is refused rather than resolved, because resolving it would read whatever directory the server happens to be standing in"
16
+ },
17
+ "model": {
18
+ "type": "string",
19
+ "description": "Model to price the totals as, e.g. the id an assistant record's `message.model` carries. Omit it and no `cost` key is reported at all; name one with no recorded rate and `cost` is `{\"unavailable\": ...}`, which is what the shipped table answers for every model"
20
+ },
21
+ "prices": {
22
+ "type": "string",
23
+ "description": "Price table to read instead of `$BANTAMKIT_PRICES` or the shipped one; only consulted when `model` is given. A malformed table is a configuration fault and stops with its own sentence, rather than being reported as an unpriced model"
24
+ }
25
+ }
26
+ },
27
+ "output_schema": {
28
+ "properties": {
29
+ "result": {
30
+ "title": "Result",
31
+ "type": "string"
32
+ }
33
+ },
34
+ "required": [
35
+ "result"
36
+ ],
37
+ "type": "object",
38
+ "title": "token_ledgerOutput"
39
+ }
40
+ }
@@ -29,4 +29,4 @@ from bantamkit.structured import StructuredOutputError, extract_json, structured
29
29
  # file as its dynamic version source, so the wheel's metadata and the string the MCP
30
30
  # server advertises are the same committed bytes, and neither is a function of when
31
31
  # someone last ran `pip`.
32
- __version__ = "0.29.2"
32
+ __version__ = "0.31.0"
@@ -30,10 +30,12 @@ THREE HARD RULES, each with the failure it prevents:
30
30
  byte-compares both runtimes' streams; one stray write breaks the wire suite. Nothing
31
31
  in this module touches `sys.stderr` or `sys.stdout`.
32
32
  * **Metadata only.** Never a tool argument's value, never a memory body, never a
33
- validated output, never a query, never a document row. Six of the eleven tools take
34
- unbounded free text and five take absolute paths (`bantamkit_read`'s `path` is one and
35
- `skill_audit`'s `root` is another; each record carries counts and tokens from a closed
36
- set, never the path, never a part name, never a skill id).
33
+ validated output, never a query, never a document row. Eight of the fourteen tools take
34
+ unbounded free text and seven take absolute paths (`bantamkit_read`'s `path` is one,
35
+ `skill_audit`'s `root` is another, `repo_map`'s `root` and `focus` are the third and
36
+ `token_ledger`'s `root` and `prices` are the fourth; each record carries counts and
37
+ tokens from a closed set, never the path, never a part name, never a skill id, never a
38
+ mapped file, never a session id, never a model name).
37
39
  Every value written here is an ASCII token from a closed
38
40
  set, an `int`, or a `bool`.
39
41
  * **Never `str(exception)`.** Only `type(exc).__name__`. This is not hypothetical: the