bantamkit 0.27.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 (192) hide show
  1. bantamkit-0.27.0/.gitignore +11 -0
  2. bantamkit-0.27.0/PKG-INFO +207 -0
  3. bantamkit-0.27.0/README.md +190 -0
  4. bantamkit-0.27.0/_assets/contracts/default.yaml +90 -0
  5. bantamkit-0.27.0/_assets/evals/devteam/manifest.yaml +351 -0
  6. bantamkit-0.27.0/_assets/evals/devteam/repo/HISTORY.md +18 -0
  7. bantamkit-0.27.0/_assets/evals/devteam/repo/README.md +12 -0
  8. bantamkit-0.27.0/_assets/evals/devteam/repo/docs/architecture.md +17 -0
  9. bantamkit-0.27.0/_assets/evals/devteam/repo/docs/runbook.md +10 -0
  10. bantamkit-0.27.0/_assets/evals/devteam/repo/issues/142-settlement-timeout.md +23 -0
  11. bantamkit-0.27.0/_assets/evals/devteam/repo/patches/0009-retry-budget.patch +38 -0
  12. bantamkit-0.27.0/_assets/evals/devteam/repo/src/ledger/__init__.py +3 -0
  13. bantamkit-0.27.0/_assets/evals/devteam/repo/src/ledger/config.py +35 -0
  14. bantamkit-0.27.0/_assets/evals/devteam/repo/src/ledger/errors.py +13 -0
  15. bantamkit-0.27.0/_assets/evals/devteam/repo/src/ledger/posting.py +12 -0
  16. bantamkit-0.27.0/_assets/evals/devteam/repo/src/ledger/registry.py +7 -0
  17. bantamkit-0.27.0/_assets/evals/devteam/repo/src/ledger/report.py +9 -0
  18. bantamkit-0.27.0/_assets/evals/devteam/repo/src/ledger/retry.py +17 -0
  19. bantamkit-0.27.0/_assets/evals/devteam/repo/src/ledger/settle.py +16 -0
  20. bantamkit-0.27.0/_assets/evals/devteam/repo/src/ledger/validate.py +14 -0
  21. bantamkit-0.27.0/_assets/evals/devteam/repo/tests/test_posting.py +13 -0
  22. bantamkit-0.27.0/_assets/evals/devteam/repo/tests/test_settle.py +9 -0
  23. bantamkit-0.27.0/_assets/evals/devteam/tasks/dt-error-contract.yaml +186 -0
  24. bantamkit-0.27.0/_assets/evals/devteam/tasks/dt-handler-map.yaml +183 -0
  25. bantamkit-0.27.0/_assets/evals/devteam/tasks/dt-patch-before-after.yaml +182 -0
  26. bantamkit-0.27.0/_assets/evals/devteam/tasks/dt-retry-attempts.yaml +181 -0
  27. bantamkit-0.27.0/_assets/evals/devteam/tasks/dt-settlement-config.yaml +185 -0
  28. bantamkit-0.27.0/_assets/evals/devteam/tasks/dt-symbol-home.yaml +181 -0
  29. bantamkit-0.27.0/_assets/evals/devteam/tasks/dt-trace-blame.yaml +182 -0
  30. bantamkit-0.27.0/_assets/evals/devteam/tasks/dt-unread-key.yaml +180 -0
  31. bantamkit-0.27.0/_assets/evals/document/tasks/doc-large-in-137.yaml +38 -0
  32. bantamkit-0.27.0/_assets/evals/document/tasks/doc-large-in-359.yaml +44 -0
  33. bantamkit-0.27.0/_assets/evals/document/tasks/doc-large-in-372.yaml +38 -0
  34. bantamkit-0.27.0/_assets/evals/document/tasks/doc-large-out-11764.yaml +37 -0
  35. bantamkit-0.27.0/_assets/evals/document/tasks/doc-large-out-4137.yaml +37 -0
  36. bantamkit-0.27.0/_assets/evals/document/tasks/doc-large-out-8022.yaml +37 -0
  37. bantamkit-0.27.0/_assets/evals/document/tasks/doc-small-137.yaml +37 -0
  38. bantamkit-0.27.0/_assets/evals/document/tasks/doc-small-261.yaml +37 -0
  39. bantamkit-0.27.0/_assets/evals/document/tasks/doc-small-388.yaml +37 -0
  40. bantamkit-0.27.0/_assets/evals/fixtures/.gitkeep +0 -0
  41. bantamkit-0.27.0/_assets/evals/fixtures/catalog.json +6 -0
  42. bantamkit-0.27.0/_assets/evals/perturbations/task-completion.yaml +576 -0
  43. bantamkit-0.27.0/_assets/evals/tasks/.gitkeep +0 -0
  44. bantamkit-0.27.0/_assets/evals/tasks/extract-contact.yaml +14 -0
  45. bantamkit-0.27.0/_assets/evals/tasks/extract-invoice.yaml +14 -0
  46. bantamkit-0.27.0/_assets/evals/tasks/extract-order.yaml +15 -0
  47. bantamkit-0.27.0/_assets/evals/tasks/extract-schedule.yaml +14 -0
  48. bantamkit-0.27.0/_assets/evals/tasks/extract-versions.yaml +17 -0
  49. bantamkit-0.27.0/_assets/evals/tasks/nav-prod-port.yaml +84 -0
  50. bantamkit-0.27.0/_assets/evals/tasks/nav-release-bundle.yaml +87 -0
  51. bantamkit-0.27.0/_assets/evals/tasks/recall-audit-retention.yaml +17 -0
  52. bantamkit-0.27.0/_assets/evals/tasks/recall-cache-ttl.yaml +13 -0
  53. bantamkit-0.27.0/_assets/evals/tasks/recall-db-port.yaml +17 -0
  54. bantamkit-0.27.0/_assets/evals/tasks/recall-deploy.yaml +13 -0
  55. bantamkit-0.27.0/_assets/evals/tasks/recall-env-endpoint.yaml +18 -0
  56. bantamkit-0.27.0/_assets/evals/tasks/recall-oncall-rotation.yaml +21 -0
  57. bantamkit-0.27.0/_assets/evals/tasks/recall-oncall.yaml +13 -0
  58. bantamkit-0.27.0/_assets/evals/tasks/recall-org-quota.yaml +18 -0
  59. bantamkit-0.27.0/_assets/evals/tasks/recall-owner.yaml +13 -0
  60. bantamkit-0.27.0/_assets/evals/tasks/shop-basket-total.yaml +10 -0
  61. bantamkit-0.27.0/_assets/evals/tasks/shop-cheapest.yaml +9 -0
  62. bantamkit-0.27.0/_assets/evals/tasks/shop-compare.yaml +9 -0
  63. bantamkit-0.27.0/_assets/evals/tasks/shop-gadget-value.yaml +9 -0
  64. bantamkit-0.27.0/_assets/evals/tasks/shop-stock-total.yaml +9 -0
  65. bantamkit-0.27.0/_assets/evals/tasks/shop-total.yaml +9 -0
  66. bantamkit-0.27.0/_assets/profiles/default.yaml +31 -0
  67. bantamkit-0.27.0/_assets/profiles/patient.yaml +31 -0
  68. bantamkit-0.27.0/_assets/rubrics/.gitkeep +0 -0
  69. bantamkit-0.27.0/_assets/rubrics/code-quality.yaml +20 -0
  70. bantamkit-0.27.0/_assets/rubrics/grounded-completion.yaml +37 -0
  71. bantamkit-0.27.0/_assets/rubrics/task-completion.yaml +28 -0
  72. bantamkit-0.27.0/_assets/schemas/shiftwork-checkpoint.json +188 -0
  73. bantamkit-0.27.0/_assets/skills/.gitkeep +0 -0
  74. bantamkit-0.27.0/_assets/skills/file-graph.md +7 -0
  75. bantamkit-0.27.0/_assets/skills/memory.md +35 -0
  76. bantamkit-0.27.0/_assets/tools/.gitkeep +0 -0
  77. bantamkit-0.27.0/_assets/tools/bantamkit_read.json +48 -0
  78. bantamkit-0.27.0/_assets/tools/bantamkit_status.json +25 -0
  79. bantamkit-0.27.0/_assets/tools/build_identity.json +17 -0
  80. bantamkit-0.27.0/_assets/tools/document_list.json +12 -0
  81. bantamkit-0.27.0/_assets/tools/document_read.json +31 -0
  82. bantamkit-0.27.0/_assets/tools/file_graph.json +12 -0
  83. bantamkit-0.27.0/_assets/tools/memory_compact.json +31 -0
  84. bantamkit-0.27.0/_assets/tools/memory_recall.json +38 -0
  85. bantamkit-0.27.0/_assets/tools/memory_save.json +61 -0
  86. bantamkit-0.27.0/_assets/tools/shiftwork_clock_in.json +25 -0
  87. bantamkit-0.27.0/_assets/tools/shiftwork_clock_out.json +60 -0
  88. bantamkit-0.27.0/_assets/tools/shiftwork_status.json +25 -0
  89. bantamkit-0.27.0/_assets/tools/skill_audit.json +70 -0
  90. bantamkit-0.27.0/_assets/tools/validate_json.json +31 -0
  91. bantamkit-0.27.0/hatch_build.py +77 -0
  92. bantamkit-0.27.0/pyproject.toml +186 -0
  93. bantamkit-0.27.0/src/bantamkit/__init__.py +32 -0
  94. bantamkit-0.27.0/src/bantamkit/agent.py +458 -0
  95. bantamkit-0.27.0/src/bantamkit/assets.py +67 -0
  96. bantamkit-0.27.0/src/bantamkit/budget.py +114 -0
  97. bantamkit-0.27.0/src/bantamkit/client.py +329 -0
  98. bantamkit-0.27.0/src/bantamkit/contract.py +522 -0
  99. bantamkit-0.27.0/src/bantamkit/criticreplay.py +3241 -0
  100. bantamkit-0.27.0/src/bantamkit/critique.py +301 -0
  101. bantamkit-0.27.0/src/bantamkit/docread.py +1744 -0
  102. bantamkit-0.27.0/src/bantamkit/evalrun.py +2003 -0
  103. bantamkit-0.27.0/src/bantamkit/eventlog.py +282 -0
  104. bantamkit-0.27.0/src/bantamkit/filegraph.py +218 -0
  105. bantamkit-0.27.0/src/bantamkit/loopguard.py +101 -0
  106. bantamkit-0.27.0/src/bantamkit/mcpreport.py +763 -0
  107. bantamkit-0.27.0/src/bantamkit/mcpserver.py +1334 -0
  108. bantamkit-0.27.0/src/bantamkit/memory/__init__.py +28 -0
  109. bantamkit-0.27.0/src/bantamkit/memory/__main__.py +291 -0
  110. bantamkit-0.27.0/src/bantamkit/memory/component.py +569 -0
  111. bantamkit-0.27.0/src/bantamkit/memory/divergence.py +744 -0
  112. bantamkit-0.27.0/src/bantamkit/memory/layers.py +257 -0
  113. bantamkit-0.27.0/src/bantamkit/memory/store.py +940 -0
  114. bantamkit-0.27.0/src/bantamkit/pdfread.py +1402 -0
  115. bantamkit-0.27.0/src/bantamkit/profile.py +46 -0
  116. bantamkit-0.27.0/src/bantamkit/shiftwork.py +212 -0
  117. bantamkit-0.27.0/src/bantamkit/skillaudit.py +853 -0
  118. bantamkit-0.27.0/src/bantamkit/statusline.py +313 -0
  119. bantamkit-0.27.0/src/bantamkit/structured.py +125 -0
  120. bantamkit-0.27.0/src/bantamkit/textutil.py +30 -0
  121. bantamkit-0.27.0/tests/cli_exit_status_probe.py +51 -0
  122. bantamkit-0.27.0/tests/conftest.py +131 -0
  123. bantamkit-0.27.0/tests/data/docread/bad-crc.docx +0 -0
  124. bantamkit-0.27.0/tests/data/docread/charref-4301-digits.html +1 -0
  125. bantamkit-0.27.0/tests/data/docread/charset-table.json +42 -0
  126. bantamkit-0.27.0/tests/data/docread/compression-method-9.docx +0 -0
  127. bantamkit-0.27.0/tests/data/docread/corrupt-deflate.docx +0 -0
  128. bantamkit-0.27.0/tests/data/docread/encrypted-member.docx +0 -0
  129. bantamkit-0.27.0/tests/data/docread/encrypted-mimetype.odt +0 -0
  130. bantamkit-0.27.0/tests/data/docread/eszett-cell-ref.xlsx +0 -0
  131. bantamkit-0.27.0/tests/data/docread/internal-dtd-entity.docx +0 -0
  132. bantamkit-0.27.0/tests/data/docread/rfc2231-charset.eml +7 -0
  133. bantamkit-0.27.0/tests/data/docread/rfc822-nested-twice.eml +30 -0
  134. bantamkit-0.27.0/tests/data/docread/unicode-digit-shared-string.xlsx +0 -0
  135. bantamkit-0.27.0/tests/data/docread/x-uuencode.eml +10 -0
  136. bantamkit-0.27.0/tests/data/f8404ab-perturbation-baseline.json +3964 -0
  137. bantamkit-0.27.0/tests/data/served-tool-surface.json +401 -0
  138. bantamkit-0.27.0/tests/docread_fixtures.py +430 -0
  139. bantamkit-0.27.0/tests/perturbation_baseline_harness.py +367 -0
  140. bantamkit-0.27.0/tests/rbp16_effect_probe.py +58 -0
  141. bantamkit-0.27.0/tests/rbp18_payload_probe.py +84 -0
  142. bantamkit-0.27.0/tests/test_adapter.py +204 -0
  143. bantamkit-0.27.0/tests/test_agent.py +905 -0
  144. bantamkit-0.27.0/tests/test_amendguard.py +582 -0
  145. bantamkit-0.27.0/tests/test_bantamkit_read_tool.py +477 -0
  146. bantamkit-0.27.0/tests/test_budget.py +285 -0
  147. bantamkit-0.27.0/tests/test_build_identity.py +460 -0
  148. bantamkit-0.27.0/tests/test_client.py +420 -0
  149. bantamkit-0.27.0/tests/test_compaction_corpus_survey.py +580 -0
  150. bantamkit-0.27.0/tests/test_conformance.py +158 -0
  151. bantamkit-0.27.0/tests/test_contract_fanout.py +364 -0
  152. bantamkit-0.27.0/tests/test_criticreplay.py +7243 -0
  153. bantamkit-0.27.0/tests/test_critique.py +663 -0
  154. bantamkit-0.27.0/tests/test_doc_commands_gate.py +207 -0
  155. bantamkit-0.27.0/tests/test_docread.py +2050 -0
  156. bantamkit-0.27.0/tests/test_document_setup.py +951 -0
  157. bantamkit-0.27.0/tests/test_document_tasks.py +271 -0
  158. bantamkit-0.27.0/tests/test_document_tools.py +1129 -0
  159. bantamkit-0.27.0/tests/test_encoding_gate.py +448 -0
  160. bantamkit-0.27.0/tests/test_evalrun.py +2511 -0
  161. bantamkit-0.27.0/tests/test_eventlog.py +750 -0
  162. bantamkit-0.27.0/tests/test_field_program_gates.py +114 -0
  163. bantamkit-0.27.0/tests/test_field_programs.py +226 -0
  164. bantamkit-0.27.0/tests/test_filegraph.py +302 -0
  165. bantamkit-0.27.0/tests/test_ladder_statistics.py +381 -0
  166. bantamkit-0.27.0/tests/test_launcher_which.py +181 -0
  167. bantamkit-0.27.0/tests/test_layers.py +733 -0
  168. bantamkit-0.27.0/tests/test_loopguard.py +308 -0
  169. bantamkit-0.27.0/tests/test_mcp_endpoint.py +484 -0
  170. bantamkit-0.27.0/tests/test_mcpdrift.py +497 -0
  171. bantamkit-0.27.0/tests/test_mcpreport.py +727 -0
  172. bantamkit-0.27.0/tests/test_mcpserver.py +719 -0
  173. bantamkit-0.27.0/tests/test_memory.py +2323 -0
  174. bantamkit-0.27.0/tests/test_memory_compact_tool.py +267 -0
  175. bantamkit-0.27.0/tests/test_memory_component.py +880 -0
  176. bantamkit-0.27.0/tests/test_memory_divergence.py +801 -0
  177. bantamkit-0.27.0/tests/test_memory_layers.py +684 -0
  178. bantamkit-0.27.0/tests/test_memory_store_tripwire.py +444 -0
  179. bantamkit-0.27.0/tests/test_mutmatrix.py +236 -0
  180. bantamkit-0.27.0/tests/test_newline_gate.py +358 -0
  181. bantamkit-0.27.0/tests/test_packaging.py +214 -0
  182. bantamkit-0.27.0/tests/test_pdfread.py +820 -0
  183. bantamkit-0.27.0/tests/test_pinharness_ledger.py +96 -0
  184. bantamkit-0.27.0/tests/test_served_tool_count_records.py +232 -0
  185. bantamkit-0.27.0/tests/test_shiftwork.py +920 -0
  186. bantamkit-0.27.0/tests/test_skillaudit.py +1492 -0
  187. bantamkit-0.27.0/tests/test_status_surface.py +542 -0
  188. bantamkit-0.27.0/tests/test_statusline.py +539 -0
  189. bantamkit-0.27.0/tests/test_structured.py +277 -0
  190. bantamkit-0.27.0/tests/test_thread_exception_gate.py +202 -0
  191. bantamkit-0.27.0/tests/test_tool_manifest.py +419 -0
  192. bantamkit-0.27.0/tests/test_version_agreement.py +94 -0
@@ -0,0 +1,11 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.egg-info/
4
+ dist/
5
+ .DS_Store
6
+ .pytest_cache/
7
+ .ruff_cache/
8
+ .superpowers/
9
+ .bantam-memory/
10
+ .bantamkit/memory/
11
+ .shiftwork/
@@ -0,0 +1,207 @@
1
+ Metadata-Version: 2.5
2
+ Name: bantamkit
3
+ Version: 0.27.0
4
+ Summary: bantamweight tooling — harness primitives that lift small-model agents
5
+ License-Expression: MIT
6
+ Requires-Python: >=3.11
7
+ Requires-Dist: httpx>=0.27
8
+ Requires-Dist: jsonschema>=4.21
9
+ Requires-Dist: pyyaml>=6.0
10
+ Provides-Extra: dev
11
+ Requires-Dist: hatchling>=1.24; extra == 'dev'
12
+ Requires-Dist: pytest>=8.0; extra == 'dev'
13
+ Requires-Dist: ruff>=0.4; extra == 'dev'
14
+ Provides-Extra: mcp
15
+ Requires-Dist: mcp<3,>=2.0; extra == 'mcp'
16
+ Description-Content-Type: text/markdown
17
+
18
+ # bantamkit
19
+
20
+ Harness primitives that lift small-model agents: a per-person memory store, JSON
21
+ validation, shift-work accounting, a document reader, and a skill-catalogue
22
+ auditor — served to any MCP host over stdio.
23
+
24
+ This is the **Python** distribution. There is a second, independent
25
+ implementation of the same surface on npm as
26
+ [`bantamkit-mcp`](https://www.npmjs.com/package/bantamkit-mcp), written in pure
27
+ Node. The two share a memory store on disk and are held to the same answers by a
28
+ conformance suite, so you can install whichever one your host makes easy. What
29
+ the two do *not* agree on is written down in
30
+ [`docs/porting.md`](https://github.com/Ink01101011/bantamkit/blob/main/docs/porting.md)
31
+ and summarised at the bottom of this page.
32
+
33
+ ## Install and run
34
+
35
+ ```bash
36
+ pipx run --spec "bantamkit[mcp]" bantamkit-mcp --assets-root
37
+ ```
38
+
39
+ or into an environment you keep:
40
+
41
+ ```bash
42
+ pip install "bantamkit[mcp]"
43
+ bantamkit-mcp --help
44
+ ```
45
+
46
+ The `[mcp]` extra pulls the MCP SDK. Without it you still get the library and the
47
+ operator CLI, but not the server.
48
+
49
+ The uv equivalent is `uvx --from "bantamkit[mcp]" bantamkit-mcp`. uv is not
50
+ installed on the machine this README was measured on, so unlike every other
51
+ command here that one is the documented form rather than a measured one.
52
+
53
+ ### Connect it to a host
54
+
55
+ Every host below runs the same command; only the file and the key around it change. If
56
+ you installed with `pip` into an environment you keep, replace the `command`/`args` pair
57
+ with the absolute path to the `bantamkit-mcp` console script in that environment.
58
+
59
+ **Claude Code** — one command, no file to edit. `-s user` makes it available in every
60
+ project; drop it for this project only.
61
+
62
+ ```bash
63
+ claude mcp add bantamkit -s user -- pipx run --spec "bantamkit[mcp]" bantamkit-mcp
64
+ ```
65
+
66
+ **Claude Desktop** — `~/Library/Application Support/Claude/claude_desktop_config.json`
67
+ on macOS, `%APPDATA%\Claude\claude_desktop_config.json` on Windows. Top-level key
68
+ `mcpServers`; each entry takes `command`, `args` and an optional `env`.
69
+
70
+ ```json
71
+ {"mcpServers": {"bantamkit": {"command": "pipx", "args": ["run", "--spec", "bantamkit[mcp]", "bantamkit-mcp"]}}}
72
+ ```
73
+
74
+ **GitHub Copilot in VS Code** — `.vscode/mcp.json` for one workspace, or the user
75
+ profile via the **MCP: Open User Configuration** command. Note the top-level key is
76
+ `servers`, not `mcpServers`.
77
+
78
+ ```json
79
+ {"servers": {"bantamkit": {"type": "stdio", "command": "pipx", "args": ["run", "--spec", "bantamkit[mcp]", "bantamkit-mcp"]}}}
80
+ ```
81
+
82
+ **Cursor** — `.cursor/mcp.json` in the project, or `~/.cursor/mcp.json` globally. Back
83
+ to `mcpServers`.
84
+
85
+ ```json
86
+ {"mcpServers": {"bantamkit": {"command": "pipx", "args": ["run", "--spec", "bantamkit[mcp]", "bantamkit-mcp"]}}}
87
+ ```
88
+
89
+ **Anything else that speaks MCP over stdio** runs the console script and talks JSON-RPC
90
+ on its stdin and stdout. Nothing about this package is host-specific.
91
+
92
+ The Claude Code and Claude Desktop forms were taken from this machine — `claude mcp add
93
+ --help` and an existing config file. The VS Code and Cursor forms are from those
94
+ projects' own documentation, not from a host installed here.
95
+
96
+ Point `--start` at a directory to choose where project-store discovery begins, or
97
+ `--store` at a single path to disable layering entirely. Do not reach for
98
+ `--store` by reflex: the default is layered, and the layering is most of the
99
+ value.
100
+
101
+ ## What it serves
102
+
103
+ Eleven tools, measured off a wheel installed into an empty virtualenv:
104
+
105
+ | tool | what it does |
106
+ |---|---|
107
+ | `memory_save` | store one durable fact, deduped and budgeted |
108
+ | `memory_recall` | retrieve facts matching a query |
109
+ | `memory_compact` | archive the stalest facts to fit the index budget |
110
+ | `validate_json` | validate a document against a JSON Schema |
111
+ | `bantamkit_read` | read a document — text, office formats, pdf |
112
+ | `skill_audit` | audit a skill catalogue for findings |
113
+ | `shiftwork_clock_in` | open a unit of work and get its brief |
114
+ | `shiftwork_clock_out` | close a unit with status and accounting |
115
+ | `shiftwork_status` | report the open cursor |
116
+ | `bantamkit_status` | report store health against its budget |
117
+ | `build_identity` | report the fingerprint of the source on disk |
118
+
119
+ `build_identity` describes the tree on disk, not the code currently executing —
120
+ useful precisely when a machine carries two installs under one name.
121
+
122
+ ## Requirements
123
+
124
+ Python 3.11 or newer. Three runtime dependencies — `httpx`, `jsonschema`,
125
+ `pyyaml` — plus `mcp` under the `[mcp]` extra.
126
+
127
+ ## The asset pack
128
+
129
+ Contracts, schemas, eval tasks, rubrics and tool manifests ship inside the
130
+ package and are located at import time:
131
+
132
+ ```bash
133
+ bantamkit-mcp --assets-root
134
+ ```
135
+
136
+ It prints the resolved directory and its file count. A build that cannot find the
137
+ pack fails rather than producing an artifact without it — that refusal is
138
+ deliberate, because the silent version of it shipped once.
139
+
140
+ `BANTAMKIT_ASSETS` overrides the location.
141
+
142
+ ## The operator CLI
143
+
144
+ Memory-store maintenance is a separate surface from the agent-facing tools, and
145
+ it is not served over MCP:
146
+
147
+ ```bash
148
+ python -m bantamkit.memory status # index size, budget, headroom, archives
149
+ python -m bantamkit.memory lint # exit 1 if malformed or over budget
150
+ python -m bantamkit.memory compact # archive the stalest facts
151
+ python -m bantamkit.memory archive <name>
152
+ python -m bantamkit.memory restore <name>
153
+ ```
154
+
155
+ `archive` moves a fact out of the store without deleting it; `restore` brings it
156
+ back by name.
157
+
158
+ ## Sharing a store with the Node server
159
+
160
+ Both distributions read and write the same on-disk format, so one store can be
161
+ served by either. That is also why a surface present in one and absent from the
162
+ other is not merely a coverage gap — it is a way for two servers to disagree
163
+ about one person's data. Every feature lands in both implementations in the same
164
+ change, and a conformance case compares the two answers before it counts as
165
+ ported.
166
+
167
+ ## Where the two implementations differ, on purpose
168
+
169
+ - **This side reads pdf, `.doc` and `.rtf`; the Node side refuses them by name.**
170
+ PDF is read by a stdlib reader written for this project; real OLE2 `.doc` and
171
+ `.rtf` go through `/usr/bin/textutil`, a macOS built-in that is probed at every
172
+ call and refused by name where it is absent.
173
+ - **The operator CLI is spelled differently**, and it shows in help text and
174
+ error messages: `python -m bantamkit.memory` here against `bantamkit-memory`
175
+ there. There is no third spelling — a pure-npm install has no Python in it, and
176
+ CPython does not install that console script.
177
+ - **`build_id` hashes the executing tree**, and the two runtimes are two trees, so
178
+ it differs by construction. `assets_digest` is identical, and that is the one
179
+ that carries meaning.
180
+
181
+ Each of these is recorded in the divergence table with a conformance case pinning
182
+ the wording, so the difference cannot drift unnoticed.
183
+
184
+ ## Development
185
+
186
+ ```bash
187
+ git clone https://github.com/Ink01101011/bantamkit
188
+ cd bantamkit
189
+ python -m venv .venv && .venv/bin/pip install -e "runtime-py[dev,mcp]"
190
+ .venv/bin/python -m pytest runtime-py/tests -q
191
+ .venv/bin/ruff check runtime-py
192
+ ```
193
+
194
+ The cross-runtime gate needs Node:
195
+
196
+ ```bash
197
+ node tools/conformance/run.mjs --all
198
+ ```
199
+
200
+ ## Links
201
+
202
+ - Source: https://github.com/Ink01101011/bantamkit
203
+ - The Node distribution: https://www.npmjs.com/package/bantamkit-mcp
204
+ - Install notes: [`docs/install.md`](https://github.com/Ink01101011/bantamkit/blob/main/docs/install.md)
205
+ - What the two runtimes disagree about: [`docs/porting.md`](https://github.com/Ink01101011/bantamkit/blob/main/docs/porting.md)
206
+
207
+ MIT.
@@ -0,0 +1,190 @@
1
+ # bantamkit
2
+
3
+ Harness primitives that lift small-model agents: a per-person memory store, JSON
4
+ validation, shift-work accounting, a document reader, and a skill-catalogue
5
+ auditor — served to any MCP host over stdio.
6
+
7
+ This is the **Python** distribution. There is a second, independent
8
+ implementation of the same surface on npm as
9
+ [`bantamkit-mcp`](https://www.npmjs.com/package/bantamkit-mcp), written in pure
10
+ Node. The two share a memory store on disk and are held to the same answers by a
11
+ conformance suite, so you can install whichever one your host makes easy. What
12
+ the two do *not* agree on is written down in
13
+ [`docs/porting.md`](https://github.com/Ink01101011/bantamkit/blob/main/docs/porting.md)
14
+ and summarised at the bottom of this page.
15
+
16
+ ## Install and run
17
+
18
+ ```bash
19
+ pipx run --spec "bantamkit[mcp]" bantamkit-mcp --assets-root
20
+ ```
21
+
22
+ or into an environment you keep:
23
+
24
+ ```bash
25
+ pip install "bantamkit[mcp]"
26
+ bantamkit-mcp --help
27
+ ```
28
+
29
+ The `[mcp]` extra pulls the MCP SDK. Without it you still get the library and the
30
+ operator CLI, but not the server.
31
+
32
+ The uv equivalent is `uvx --from "bantamkit[mcp]" bantamkit-mcp`. uv is not
33
+ installed on the machine this README was measured on, so unlike every other
34
+ command here that one is the documented form rather than a measured one.
35
+
36
+ ### Connect it to a host
37
+
38
+ Every host below runs the same command; only the file and the key around it change. If
39
+ you installed with `pip` into an environment you keep, replace the `command`/`args` pair
40
+ with the absolute path to the `bantamkit-mcp` console script in that environment.
41
+
42
+ **Claude Code** — one command, no file to edit. `-s user` makes it available in every
43
+ project; drop it for this project only.
44
+
45
+ ```bash
46
+ claude mcp add bantamkit -s user -- pipx run --spec "bantamkit[mcp]" bantamkit-mcp
47
+ ```
48
+
49
+ **Claude Desktop** — `~/Library/Application Support/Claude/claude_desktop_config.json`
50
+ on macOS, `%APPDATA%\Claude\claude_desktop_config.json` on Windows. Top-level key
51
+ `mcpServers`; each entry takes `command`, `args` and an optional `env`.
52
+
53
+ ```json
54
+ {"mcpServers": {"bantamkit": {"command": "pipx", "args": ["run", "--spec", "bantamkit[mcp]", "bantamkit-mcp"]}}}
55
+ ```
56
+
57
+ **GitHub Copilot in VS Code** — `.vscode/mcp.json` for one workspace, or the user
58
+ profile via the **MCP: Open User Configuration** command. Note the top-level key is
59
+ `servers`, not `mcpServers`.
60
+
61
+ ```json
62
+ {"servers": {"bantamkit": {"type": "stdio", "command": "pipx", "args": ["run", "--spec", "bantamkit[mcp]", "bantamkit-mcp"]}}}
63
+ ```
64
+
65
+ **Cursor** — `.cursor/mcp.json` in the project, or `~/.cursor/mcp.json` globally. Back
66
+ to `mcpServers`.
67
+
68
+ ```json
69
+ {"mcpServers": {"bantamkit": {"command": "pipx", "args": ["run", "--spec", "bantamkit[mcp]", "bantamkit-mcp"]}}}
70
+ ```
71
+
72
+ **Anything else that speaks MCP over stdio** runs the console script and talks JSON-RPC
73
+ on its stdin and stdout. Nothing about this package is host-specific.
74
+
75
+ The Claude Code and Claude Desktop forms were taken from this machine — `claude mcp add
76
+ --help` and an existing config file. The VS Code and Cursor forms are from those
77
+ projects' own documentation, not from a host installed here.
78
+
79
+ Point `--start` at a directory to choose where project-store discovery begins, or
80
+ `--store` at a single path to disable layering entirely. Do not reach for
81
+ `--store` by reflex: the default is layered, and the layering is most of the
82
+ value.
83
+
84
+ ## What it serves
85
+
86
+ Eleven tools, measured off a wheel installed into an empty virtualenv:
87
+
88
+ | tool | what it does |
89
+ |---|---|
90
+ | `memory_save` | store one durable fact, deduped and budgeted |
91
+ | `memory_recall` | retrieve facts matching a query |
92
+ | `memory_compact` | archive the stalest facts to fit the index budget |
93
+ | `validate_json` | validate a document against a JSON Schema |
94
+ | `bantamkit_read` | read a document — text, office formats, pdf |
95
+ | `skill_audit` | audit a skill catalogue for findings |
96
+ | `shiftwork_clock_in` | open a unit of work and get its brief |
97
+ | `shiftwork_clock_out` | close a unit with status and accounting |
98
+ | `shiftwork_status` | report the open cursor |
99
+ | `bantamkit_status` | report store health against its budget |
100
+ | `build_identity` | report the fingerprint of the source on disk |
101
+
102
+ `build_identity` describes the tree on disk, not the code currently executing —
103
+ useful precisely when a machine carries two installs under one name.
104
+
105
+ ## Requirements
106
+
107
+ Python 3.11 or newer. Three runtime dependencies — `httpx`, `jsonschema`,
108
+ `pyyaml` — plus `mcp` under the `[mcp]` extra.
109
+
110
+ ## The asset pack
111
+
112
+ Contracts, schemas, eval tasks, rubrics and tool manifests ship inside the
113
+ package and are located at import time:
114
+
115
+ ```bash
116
+ bantamkit-mcp --assets-root
117
+ ```
118
+
119
+ It prints the resolved directory and its file count. A build that cannot find the
120
+ pack fails rather than producing an artifact without it — that refusal is
121
+ deliberate, because the silent version of it shipped once.
122
+
123
+ `BANTAMKIT_ASSETS` overrides the location.
124
+
125
+ ## The operator CLI
126
+
127
+ Memory-store maintenance is a separate surface from the agent-facing tools, and
128
+ it is not served over MCP:
129
+
130
+ ```bash
131
+ python -m bantamkit.memory status # index size, budget, headroom, archives
132
+ python -m bantamkit.memory lint # exit 1 if malformed or over budget
133
+ python -m bantamkit.memory compact # archive the stalest facts
134
+ python -m bantamkit.memory archive <name>
135
+ python -m bantamkit.memory restore <name>
136
+ ```
137
+
138
+ `archive` moves a fact out of the store without deleting it; `restore` brings it
139
+ back by name.
140
+
141
+ ## Sharing a store with the Node server
142
+
143
+ Both distributions read and write the same on-disk format, so one store can be
144
+ served by either. That is also why a surface present in one and absent from the
145
+ other is not merely a coverage gap — it is a way for two servers to disagree
146
+ about one person's data. Every feature lands in both implementations in the same
147
+ change, and a conformance case compares the two answers before it counts as
148
+ ported.
149
+
150
+ ## Where the two implementations differ, on purpose
151
+
152
+ - **This side reads pdf, `.doc` and `.rtf`; the Node side refuses them by name.**
153
+ PDF is read by a stdlib reader written for this project; real OLE2 `.doc` and
154
+ `.rtf` go through `/usr/bin/textutil`, a macOS built-in that is probed at every
155
+ call and refused by name where it is absent.
156
+ - **The operator CLI is spelled differently**, and it shows in help text and
157
+ error messages: `python -m bantamkit.memory` here against `bantamkit-memory`
158
+ there. There is no third spelling — a pure-npm install has no Python in it, and
159
+ CPython does not install that console script.
160
+ - **`build_id` hashes the executing tree**, and the two runtimes are two trees, so
161
+ it differs by construction. `assets_digest` is identical, and that is the one
162
+ that carries meaning.
163
+
164
+ Each of these is recorded in the divergence table with a conformance case pinning
165
+ the wording, so the difference cannot drift unnoticed.
166
+
167
+ ## Development
168
+
169
+ ```bash
170
+ git clone https://github.com/Ink01101011/bantamkit
171
+ cd bantamkit
172
+ python -m venv .venv && .venv/bin/pip install -e "runtime-py[dev,mcp]"
173
+ .venv/bin/python -m pytest runtime-py/tests -q
174
+ .venv/bin/ruff check runtime-py
175
+ ```
176
+
177
+ The cross-runtime gate needs Node:
178
+
179
+ ```bash
180
+ node tools/conformance/run.mjs --all
181
+ ```
182
+
183
+ ## Links
184
+
185
+ - Source: https://github.com/Ink01101011/bantamkit
186
+ - The Node distribution: https://www.npmjs.com/package/bantamkit-mcp
187
+ - Install notes: [`docs/install.md`](https://github.com/Ink01101011/bantamkit/blob/main/docs/install.md)
188
+ - What the two runtimes disagree about: [`docs/porting.md`](https://github.com/Ink01101011/bantamkit/blob/main/docs/porting.md)
189
+
190
+ MIT.
@@ -0,0 +1,90 @@
1
+ name: default
2
+ schema_instruction: "Return ONLY a JSON object matching this JSON Schema. No prose.\n"
3
+ schema_retry: "{error}\nReturn ONLY a JSON object matching the schema."
4
+ critique_feedback: "A reviewer scored your answer {score}/10 (needs >= {threshold}). Feedback: {feedback}\nIf the feedback says a value is missing, unverified, or absent from your evidence, that is a fact you never looked up: call your tools and read the source that has it. Do not reword, generalise, or hedge the previous answer to work around the gap. Then answer again."
5
+ parse_error: "output was not parseable JSON: {detail}"
6
+ validation_error: "JSON does not match schema at '{where}': {detail}"
7
+ json_answer_retry: "Your answer contains no JSON. Restate your final answer as ONLY the JSON requested by the task, with no prose around it."
8
+ loop_note: "(you have now received this exact result {count} times; it will not change. Do something different or give your final answer now)"
9
+ loop_warn: "(STOP calling tools. Give your final answer now, in exactly the format the task asked for.)"
10
+ evidence_line: "{name}({arguments}) -> {observation}"
11
+ evidence_no_observation: "(no observation)"
12
+ evidence_empty: "(no tool calls were made)"
13
+ # The document reader pair's observations (`document_list`, `document_read`). Every string a
14
+ # reader hands back to the model lives here and not in the harness, for the reason the layer
15
+ # rule gives: the mechanics measured in `docread.py` transfer across models, this wording is
16
+ # exactly what does not.
17
+ document_manifest_empty: "no documents are attached to this task"
18
+ document_manifest_part: "{document} ({kind}) part {index} \"{part}\": {rows} rows, numbered 0 to {last}"
19
+ document_manifest_header_row: " row 0 is the header: {row}"
20
+ document_manifest_first_row: " row 1 is the first data row: {row}"
21
+ document_manifest_last_row: " row {index} is the last data row: {row}"
22
+ # What the rendering left out, stated in the one place that says what exists. Measured need
23
+ # (J25, the user's real ~/Downloads, 2026-08-20): `step test.xlsx` is 18.62 MB and the manifest
24
+ # said `4 parts, 28 rows` — all 28 of those rows are empty lines and the file's actual content
25
+ # is 56 embedded PNGs. Every line here is a COUNT: an adjective ("some images") tells a model
26
+ # nothing it can decide with, and silence tells it something false.
27
+ document_manifest_package_media: "{document}: the file also holds {count} embedded file(s) ({what}) totalling {bytes} bytes, which no row can carry — this reader renders no image or embedded object"
28
+ document_manifest_omitted_media: " NOT in those rows: {count} embedded file(s), {bytes} bytes, anchored to this part"
29
+ document_manifest_omitted_blank: " {count} of those {rows} rows carry no cell value at all and render as an empty line"
30
+ document_manifest_omitted_format: " column(s) {where}: {count} cell(s) store a NUMBER under the date/time format {what} — this reader renders the stored serial number verbatim and does not convert it to a date; convert it with that format code if you need one"
31
+ # J25-D3, the PDF reader. Two silences a page-addressable reader can produce that a
32
+ # spreadsheet cannot: a page that rendered no row (a scan, or glyphs no font maps), and
33
+ # characters dropped because the file states no mapping for them. An empty page and a page
34
+ # nobody could read are different facts and the model must be able to tell them apart.
35
+ document_manifest_omitted_unread_page: " this part rendered NO row: {why}. It draws {count} image(s), {bytes} bytes, that no row can carry — no row means this reader recovered no text from the page, which is NOT the same as the page being empty, and there is no OCR here"
36
+ document_manifest_unread_no_operator: "the page ran no text-showing operator at all, so nothing on it was ever text"
37
+ document_manifest_unread_unmapped: "the page ran {show_ops} text-showing operator(s) and every one of the {unmapped} character(s) they showed came through a font that declares no character map, so this reader dropped them rather than guess at them"
38
+ document_manifest_unread_whitespace: "the page ran {show_ops} text-showing operator(s) and this reader mapped every one of the {vouched} character(s) they showed, and every one of those characters is WHITESPACE — the text was recovered and it carries nothing, which is a fact about the page and not a failure of this reader"
39
+ document_manifest_unread_no_character: "the page ran {show_ops} text-showing operator(s) that put no character on the page at all, neither one this reader could map nor one it had to drop"
40
+ document_manifest_omitted_unmapped: " {count} character(s) shown on this part are NOT in those rows: their codes came from font(s) with no /ToUnicode map ({what}), so the file stores indices into a font's own glyphs and says nowhere which character each glyph draws — this reader drops them rather than guess, because a guess here is indistinguishable from content"
41
+ document_manifest_omitted_other: " NOT in those rows: {count} {subject} ({what})"
42
+ document_page_header: "{document} \"{part}\" rows {start}-{end} of {rows}; each line below begins with its own row number"
43
+ document_page_next: "more rows follow: call document_read again with offset={next_offset}"
44
+ document_page_end: "that was the last row of \"{part}\""
45
+ document_page_truncated: "row {index} was too long for one page and was cut: {dropped} bytes dropped"
46
+ document_unknown: "error: no document named {name}; this task has: {available}"
47
+ document_offset_past_end: "error: offset {offset} is past the end of \"{part}\", which has {rows} rows numbered 0 to {last}"
48
+ document_error: "error: {detail}"
49
+ # `bantamkit_read` (the MCP reader, job43) reuses every `document_*` sentence above with the
50
+ # path standing in for `{document}`. Two sentences are genuinely its own: its continuation
51
+ # line names ITS tool, and a part it does not have is a fact about the file, not the task.
52
+ bantamkit_read_page_next: "more rows follow: call bantamkit_read again with offset={next_offset}"
53
+ bantamkit_read_unknown_part: "error: no part named \"{part}\" in {path}; it has: {available}"
54
+ # The `paste` arm's system message (`docs/eval-data/2026-08-20-document-read-bar.md` §10.2,
55
+ # PASTE_MAX_BYTES = 8621 under Amendment 1, 2026-08-20). The arm registers NO tools, so these four lines are the whole of
56
+ # what the model is told ABOUT the corpus; the rows themselves are docread's own rendering,
57
+ # unprefixed and unreformatted, so `paste` and `document_read` differ in DELIVERY and not in
58
+ # content. Clause 4 makes stating the paste's own completeness part of the contract, and
59
+ # `paste_truncated` says the missing rows are unreachable rather than leaving the model to
60
+ # hunt for a tool that is not there: a paste that lets a truncated head read as the whole
61
+ # sheet is a different, worse arm than the one the bar pre-registered.
62
+ document_paste_preamble: "The following document content is attached to this task. Fields in a row are separated by tabs, rows are given in order, and row 0 of each part is its header."
63
+ document_paste_part: "{document} ({kind}) part {index} \"{part}\": {rows} rows, numbered 0 to {last}; {shown} of them are shown below."
64
+ document_paste_complete: " rows 0 to {last_shown} are shown, which is every row of \"{part}\": this copy is COMPLETE."
65
+ document_paste_truncated: " rows 0 to {last_shown} are shown; rows {first_missing} to {last} of \"{part}\" are NOT shown and no tool is attached that can fetch them. This copy is PARTIAL."
66
+ document_paste_none: " no rows of \"{part}\" are shown and no tool is attached that can fetch them."
67
+ # What the model is told when a tool CALL cannot be made or fails, rather than when a tool
68
+ # answers with its own error (`document_unknown` and friends above are that). It lives here
69
+ # for the reason the layer rule gives and for one measured reason: before 2026-08-20 the
70
+ # dispatcher formatted this sentence itself and interpolated the raw exception, so a model
71
+ # that sent one extra argument was handed
72
+ # `_document_tools.<locals>.list_documents() got an unexpected keyword argument 'document'`
73
+ # — a Python qualname, model-facing, owned by no asset and pinned by no golden. The
74
+ # argument-shaped failures are intercepted before the handler is called now, so `{detail}`
75
+ # carries a handler's OWN sentence and no longer a signature fragment.
76
+ tool_failed: "error: {tool} failed: {detail}. fix the arguments and retry."
77
+ tool_arguments: "error: {tool} does not take the arguments it was given. it takes: {accepts}. fix the arguments and retry."
78
+ tool_arguments_none: "error: {tool} takes no arguments at all. call it with none and retry."
79
+ # 2026-08-20, `RB-P86`. The sibling of the two above, one layer in. `select_declared_arguments`
80
+ # drops keys the schema does not declare and type-checks nothing, so `llama3.2:3b` — which
81
+ # emits a JSON-Schema FRAGMENT as the value of a declared parameter,
82
+ # `{"document": {"description": "stock", "type": "string"}}` — got its dict straight through to
83
+ # `docs.get(name)` and the model read `unhashable type: 'dict'`, thirteen times over 432 graded
84
+ # runs. That is CPython's sentence about a hash table, not a tool's sentence about its own
85
+ # arguments, and a 3b that receives it stops calling tools and answers that it cannot access
86
+ # the workbook. What it is told now names the argument, the type the tool declares and the type
87
+ # it was sent, so the next turn has something to correct. One frame for one or many, because
88
+ # the count is not the thing the model has to act on.
89
+ tool_argument_types: "error: {tool} was called with the wrong type of argument. {problems}. fix the arguments and retry."
90
+ tool_argument_type: "{argument} must be type {expected}, not type {actual}"