bantamkit 0.34.2__tar.gz → 0.35.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.
- {bantamkit-0.34.2 → bantamkit-0.35.0}/PKG-INFO +16 -13
- {bantamkit-0.34.2 → bantamkit-0.35.0}/README.md +15 -12
- bantamkit-0.35.0/_assets/tools/shiftwork_plan.json +25 -0
- bantamkit-0.35.0/_assets/tools/work_plan.json +49 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/__init__.py +1 -1
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/eventlog.py +12 -9
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/mcpserver.py +21 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/memory/__main__.py +1 -1
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/memory/store.py +50 -3
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/shiftwork.py +68 -1
- bantamkit-0.35.0/src/bantamkit/workplan.py +157 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/data/served-tool-surface.json +69 -1
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_bantamkit_gitignore.py +64 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_eventlog.py +1 -1
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_layers.py +4 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_mcpserver.py +10 -3
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_memory_compact_tool.py +3 -1
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_served_tool_count_records.py +144 -18
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_shiftwork.py +167 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_skillaudit.py +13 -3
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_status_surface.py +1 -1
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_tokenledger.py +2 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_tool_manifest.py +2 -0
- bantamkit-0.35.0/tests/test_workplan.py +341 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/.gitignore +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/contracts/default.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/manifest.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/repo/HISTORY.md +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/repo/README.md +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/repo/docs/architecture.md +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/repo/docs/runbook.md +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/repo/issues/142-settlement-timeout.md +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/repo/patches/0009-retry-budget.patch +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/repo/src/ledger/__init__.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/repo/src/ledger/config.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/repo/src/ledger/errors.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/repo/src/ledger/posting.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/repo/src/ledger/registry.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/repo/src/ledger/report.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/repo/src/ledger/retry.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/repo/src/ledger/settle.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/repo/src/ledger/validate.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/repo/tests/test_posting.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/repo/tests/test_settle.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/tasks/dt-error-contract.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/tasks/dt-handler-map.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/tasks/dt-patch-before-after.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/tasks/dt-retry-attempts.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/tasks/dt-settlement-config.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/tasks/dt-symbol-home.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/tasks/dt-trace-blame.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/devteam/tasks/dt-unread-key.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/document/tasks/doc-large-in-137.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/document/tasks/doc-large-in-359.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/document/tasks/doc-large-in-372.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/document/tasks/doc-large-out-11764.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/document/tasks/doc-large-out-4137.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/document/tasks/doc-large-out-8022.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/document/tasks/doc-small-137.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/document/tasks/doc-small-261.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/document/tasks/doc-small-388.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/fixtures/.gitkeep +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/fixtures/catalog.json +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/perturbations/task-completion.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/tasks/.gitkeep +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/tasks/extract-contact.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/tasks/extract-invoice.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/tasks/extract-order.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/tasks/extract-schedule.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/tasks/extract-versions.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/tasks/nav-prod-port.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/tasks/nav-release-bundle.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/tasks/recall-audit-retention.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/tasks/recall-cache-ttl.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/tasks/recall-db-port.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/tasks/recall-deploy.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/tasks/recall-env-endpoint.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/tasks/recall-oncall-rotation.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/tasks/recall-oncall.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/tasks/recall-org-quota.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/tasks/recall-owner.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/tasks/shop-basket-total.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/tasks/shop-cheapest.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/tasks/shop-compare.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/tasks/shop-gadget-value.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/tasks/shop-stock-total.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/evals/tasks/shop-total.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/pricing/default.json +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/profiles/default.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/profiles/patient.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/rubrics/.gitkeep +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/rubrics/code-quality.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/rubrics/grounded-completion.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/rubrics/task-completion.yaml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/schemas/shiftwork-checkpoint.json +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/skills/.gitkeep +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/skills/file-graph.md +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/skills/memory.md +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/tools/.gitkeep +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/tools/bantamkit_read.json +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/tools/bantamkit_status.json +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/tools/build_identity.json +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/tools/document_list.json +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/tools/document_read.json +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/tools/file_graph.json +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/tools/memory_compact.json +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/tools/memory_dream.json +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/tools/memory_recall.json +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/tools/memory_save.json +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/tools/repo_map.json +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/tools/shiftwork_clock_in.json +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/tools/shiftwork_clock_out.json +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/tools/shiftwork_status.json +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/tools/skill_audit.json +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/tools/token_ledger.json +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/_assets/tools/validate_json.json +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/hatch_build.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/pyproject.toml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/agent.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/assets.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/budget.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/client.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/contract.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/criticreplay.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/critique.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/docmanifest.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/docread.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/evalrun.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/filegraph.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/hostinstall.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/loopguard.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/mcpreport.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/memory/__init__.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/memory/component.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/memory/divergence.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/memory/dream.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/memory/layers.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/pdfread.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/pricing.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/profile.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/repomap.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/selfupdate.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/skillaudit.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/statusline.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/structured.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/textutil.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/src/bantamkit/tokenledger.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/cli_exit_status_probe.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/conftest.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/data/docread/bad-crc.docx +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/data/docread/charref-4301-digits.html +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/data/docread/charset-table.json +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/data/docread/compression-method-9.docx +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/data/docread/corrupt-deflate.docx +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/data/docread/encrypted-member.docx +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/data/docread/encrypted-mimetype.odt +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/data/docread/eszett-cell-ref.xlsx +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/data/docread/internal-dtd-entity.docx +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/data/docread/rfc2231-charset.eml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/data/docread/rfc822-nested-twice.eml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/data/docread/unicode-digit-shared-string.xlsx +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/data/docread/x-uuencode.eml +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/data/f8404ab-perturbation-baseline.json +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/data/platform-assumption-baseline.json +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/docread_fixtures.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/perturbation_baseline_harness.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/rbp16_effect_probe.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/rbp18_payload_probe.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_adapter.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_agent.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_amendguard.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_bantamkit_read_tool.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_budget.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_build_identity.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_client.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_compaction_corpus_survey.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_conformance.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_conformance_harness_resilience.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_conformance_suite_table_gate.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_contract_fanout.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_criticreplay.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_critique.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_doc_commands_gate.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_docread.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_docread_ceilings.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_document_manifest_parity.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_document_setup.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_document_tasks.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_document_tools.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_encoding_gate.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_evalrun.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_field_program_gates.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_field_programs.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_filegraph.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_hostinstall.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_install_shape.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_ladder_statistics.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_launcher_which.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_loopguard.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_mcp_endpoint.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_mcpdrift.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_mcpreport.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_memory.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_memory_component.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_memory_divergence.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_memory_dream.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_memory_layers.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_memory_store_tripwire.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_mutmatrix.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_newline_gate.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_packaging.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_pdfread.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_pinharness_ledger.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_platform_assumption_gate.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_pricing.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_repo_map_tool.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_repomap.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_selfupdate.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_statusline.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_structured.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_thread_exception_gate.py +0 -0
- {bantamkit-0.34.2 → bantamkit-0.35.0}/tests/test_version_agreement.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: bantamkit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.35.0
|
|
4
4
|
Summary: Memory MCP server for Claude Code, Cursor, VS Code Copilot and Claude Desktop, plus a Python library that lifts small-model agents. Install once, run offline.
|
|
5
5
|
Project-URL: Homepage, https://github.com/Ink01101011/bantamkit
|
|
6
6
|
Project-URL: Repository, https://github.com/Ink01101011/bantamkit
|
|
@@ -55,7 +55,7 @@ easy.
|
|
|
55
55
|
| [Configuration](#configuration) | Every flag and variable, with its default |
|
|
56
56
|
| [Update](#update) | `--update`, pipx, uv, then restart |
|
|
57
57
|
| [Troubleshooting](#troubleshooting) | Timeouts, refusals, the wrong store |
|
|
58
|
-
| [What it serves](#what-it-serves) |
|
|
58
|
+
| [What it serves](#what-it-serves) | 14 tools, one prompt, two resource templates |
|
|
59
59
|
| [Requirements](#requirements) | Python and dependencies |
|
|
60
60
|
| [The asset pack](#the-asset-pack) | `--assets-root`, `BANTAMKIT_ASSETS` |
|
|
61
61
|
| [The operator CLI: `python -m bantamkit.memory`](#the-operator-cli-python--m-bantamkitmemory) | status, lint, compact, archived, archive, restore |
|
|
@@ -88,7 +88,8 @@ python -m venv <env>
|
|
|
88
88
|
```
|
|
89
89
|
|
|
90
90
|
`--install` records the venv's console script by absolute path with `"args": []`, so no launch
|
|
91
|
-
needs the network or your shell's PATH. Measured on macOS arm64
|
|
91
|
+
needs the network or your shell's PATH. Measured on macOS arm64 (served-tools: dated — the
|
|
92
|
+
surface was twelve then), it served 12 tools under a GUI
|
|
92
93
|
app's PATH, `/usr/bin:/bin:/usr/sbin:/sbin`; the Windows layout (`<env>\Scripts\`) was not.
|
|
93
94
|
|
|
94
95
|
**No network on the target? Carry a wheelhouse.** Download it on a machine with the **same OS,
|
|
@@ -96,9 +97,9 @@ CPU architecture and Python minor version** (some wheels, such as `pydantic_core
|
|
|
96
97
|
one platform only), copy `wheels/` across, and install from it:
|
|
97
98
|
|
|
98
99
|
```bash
|
|
99
|
-
python -m pip download "bantamkit[mcp]==0.
|
|
100
|
+
python -m pip download "bantamkit[mcp]==0.35.0" -d wheels
|
|
100
101
|
python -m venv <env>
|
|
101
|
-
<env>/bin/pip install --no-index --find-links wheels "bantamkit[mcp]==0.
|
|
102
|
+
<env>/bin/pip install --no-index --find-links wheels "bantamkit[mcp]==0.35.0"
|
|
102
103
|
<env>/bin/bantamkit-mcp --install cursor
|
|
103
104
|
```
|
|
104
105
|
|
|
@@ -247,10 +248,10 @@ pipx upgrade bantamkit # pipx
|
|
|
247
248
|
uv tool upgrade bantamkit # uv
|
|
248
249
|
```
|
|
249
250
|
|
|
250
|
-
`--update` (`check the package index and update this install if it differs, then exit`)
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
the download and install.
|
|
251
|
+
`--update` (`check the package index and update this install if it differs, then exit`) upgrades
|
|
252
|
+
an install from PyPI with this interpreter's pip; it is the only network access here. An editable
|
|
253
|
+
install, a local file or a source tree is refused with exit 1 and a sentence naming the manual
|
|
254
|
+
route (for a clone, `git pull`). For a wheelhouse, repeat the download and install.
|
|
254
255
|
|
|
255
256
|
**Then restart the server in the host** (`/mcp` → reconnect in Claude Code; fully restart Claude
|
|
256
257
|
Desktop). `bantamkit_status` prints the version **and the `build_id` of the code answering
|
|
@@ -272,7 +273,7 @@ you**; a new version with an old `build_id` means an old process.
|
|
|
272
273
|
|
|
273
274
|
## What it serves
|
|
274
275
|
|
|
275
|
-
|
|
276
|
+
It serves 14 tools, the `bantamkit_status` prompt and two resource templates
|
|
276
277
|
(`bantamkit://skills/{name}`, `bantamkit://rubrics/{name}`):
|
|
277
278
|
|
|
278
279
|
| Tool | What it does |
|
|
@@ -286,9 +287,11 @@ you**; a new version with an old `build_id` means an old process.
|
|
|
286
287
|
| `shiftwork_clock_in` | open a unit of work and get its brief |
|
|
287
288
|
| `shiftwork_clock_out` | close a unit with status and accounting |
|
|
288
289
|
| `shiftwork_status` | report the open cursor |
|
|
290
|
+
| `shiftwork_plan` | read-only: which units of a checkpoint its `depends_on` graph permits to run at once. Never moves the cursor |
|
|
291
|
+
| `work_plan` | turn any `{id, depends_on, priority}` graph into the batches that may run in parallel, plus the widest fan-out |
|
|
289
292
|
| `token_ledger` | what a session cost, read off the host's transcripts |
|
|
290
293
|
| `bantamkit_status` | report store health against its budget |
|
|
291
|
-
| `build_identity` | report the fingerprint of the source on disk, not the executing code |
|
|
294
|
+
| `build_identity` | report the fingerprint of the source on disk, not the executing code — useful when a machine carries two installs under one name |
|
|
292
295
|
|
|
293
296
|
The document reader `bantamkit_read` left the served tools in job50 (2026-09-12) and stays in the
|
|
294
297
|
library as `bantamkit.docread`.
|
|
@@ -303,7 +306,7 @@ under the `[mcp]` extra.
|
|
|
303
306
|
Contracts, schemas, eval tasks, rubrics and tool manifests ship inside the package.
|
|
304
307
|
`bantamkit-mcp --assets-root` prints the resolved directory and its file count, and
|
|
305
308
|
`BANTAMKIT_ASSETS` overrides it. A build that cannot find the pack fails instead of shipping
|
|
306
|
-
without it.
|
|
309
|
+
without it — deliberately, because the silent version shipped once.
|
|
307
310
|
|
|
308
311
|
## The operator CLI: `python -m bantamkit.memory`
|
|
309
312
|
|
|
@@ -342,7 +345,7 @@ git clone https://github.com/Ink01101011/bantamkit
|
|
|
342
345
|
cd bantamkit
|
|
343
346
|
python -m venv .venv && .venv/bin/pip install -e "runtime-py[dev,mcp]"
|
|
344
347
|
.venv/bin/python -m pytest runtime-py/tests -q
|
|
345
|
-
.venv/bin/ruff check runtime-py
|
|
348
|
+
.venv/bin/ruff check runtime-py tools
|
|
346
349
|
```
|
|
347
350
|
|
|
348
351
|
The cross-runtime gate needs Node:
|
|
@@ -27,7 +27,7 @@ easy.
|
|
|
27
27
|
| [Configuration](#configuration) | Every flag and variable, with its default |
|
|
28
28
|
| [Update](#update) | `--update`, pipx, uv, then restart |
|
|
29
29
|
| [Troubleshooting](#troubleshooting) | Timeouts, refusals, the wrong store |
|
|
30
|
-
| [What it serves](#what-it-serves) |
|
|
30
|
+
| [What it serves](#what-it-serves) | 14 tools, one prompt, two resource templates |
|
|
31
31
|
| [Requirements](#requirements) | Python and dependencies |
|
|
32
32
|
| [The asset pack](#the-asset-pack) | `--assets-root`, `BANTAMKIT_ASSETS` |
|
|
33
33
|
| [The operator CLI: `python -m bantamkit.memory`](#the-operator-cli-python--m-bantamkitmemory) | status, lint, compact, archived, archive, restore |
|
|
@@ -60,7 +60,8 @@ python -m venv <env>
|
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
`--install` records the venv's console script by absolute path with `"args": []`, so no launch
|
|
63
|
-
needs the network or your shell's PATH. Measured on macOS arm64
|
|
63
|
+
needs the network or your shell's PATH. Measured on macOS arm64 (served-tools: dated — the
|
|
64
|
+
surface was twelve then), it served 12 tools under a GUI
|
|
64
65
|
app's PATH, `/usr/bin:/bin:/usr/sbin:/sbin`; the Windows layout (`<env>\Scripts\`) was not.
|
|
65
66
|
|
|
66
67
|
**No network on the target? Carry a wheelhouse.** Download it on a machine with the **same OS,
|
|
@@ -68,9 +69,9 @@ CPU architecture and Python minor version** (some wheels, such as `pydantic_core
|
|
|
68
69
|
one platform only), copy `wheels/` across, and install from it:
|
|
69
70
|
|
|
70
71
|
```bash
|
|
71
|
-
python -m pip download "bantamkit[mcp]==0.
|
|
72
|
+
python -m pip download "bantamkit[mcp]==0.35.0" -d wheels
|
|
72
73
|
python -m venv <env>
|
|
73
|
-
<env>/bin/pip install --no-index --find-links wheels "bantamkit[mcp]==0.
|
|
74
|
+
<env>/bin/pip install --no-index --find-links wheels "bantamkit[mcp]==0.35.0"
|
|
74
75
|
<env>/bin/bantamkit-mcp --install cursor
|
|
75
76
|
```
|
|
76
77
|
|
|
@@ -219,10 +220,10 @@ pipx upgrade bantamkit # pipx
|
|
|
219
220
|
uv tool upgrade bantamkit # uv
|
|
220
221
|
```
|
|
221
222
|
|
|
222
|
-
`--update` (`check the package index and update this install if it differs, then exit`)
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
the download and install.
|
|
223
|
+
`--update` (`check the package index and update this install if it differs, then exit`) upgrades
|
|
224
|
+
an install from PyPI with this interpreter's pip; it is the only network access here. An editable
|
|
225
|
+
install, a local file or a source tree is refused with exit 1 and a sentence naming the manual
|
|
226
|
+
route (for a clone, `git pull`). For a wheelhouse, repeat the download and install.
|
|
226
227
|
|
|
227
228
|
**Then restart the server in the host** (`/mcp` → reconnect in Claude Code; fully restart Claude
|
|
228
229
|
Desktop). `bantamkit_status` prints the version **and the `build_id` of the code answering
|
|
@@ -244,7 +245,7 @@ you**; a new version with an old `build_id` means an old process.
|
|
|
244
245
|
|
|
245
246
|
## What it serves
|
|
246
247
|
|
|
247
|
-
|
|
248
|
+
It serves 14 tools, the `bantamkit_status` prompt and two resource templates
|
|
248
249
|
(`bantamkit://skills/{name}`, `bantamkit://rubrics/{name}`):
|
|
249
250
|
|
|
250
251
|
| Tool | What it does |
|
|
@@ -258,9 +259,11 @@ you**; a new version with an old `build_id` means an old process.
|
|
|
258
259
|
| `shiftwork_clock_in` | open a unit of work and get its brief |
|
|
259
260
|
| `shiftwork_clock_out` | close a unit with status and accounting |
|
|
260
261
|
| `shiftwork_status` | report the open cursor |
|
|
262
|
+
| `shiftwork_plan` | read-only: which units of a checkpoint its `depends_on` graph permits to run at once. Never moves the cursor |
|
|
263
|
+
| `work_plan` | turn any `{id, depends_on, priority}` graph into the batches that may run in parallel, plus the widest fan-out |
|
|
261
264
|
| `token_ledger` | what a session cost, read off the host's transcripts |
|
|
262
265
|
| `bantamkit_status` | report store health against its budget |
|
|
263
|
-
| `build_identity` | report the fingerprint of the source on disk, not the executing code |
|
|
266
|
+
| `build_identity` | report the fingerprint of the source on disk, not the executing code — useful when a machine carries two installs under one name |
|
|
264
267
|
|
|
265
268
|
The document reader `bantamkit_read` left the served tools in job50 (2026-09-12) and stays in the
|
|
266
269
|
library as `bantamkit.docread`.
|
|
@@ -275,7 +278,7 @@ under the `[mcp]` extra.
|
|
|
275
278
|
Contracts, schemas, eval tasks, rubrics and tool manifests ship inside the package.
|
|
276
279
|
`bantamkit-mcp --assets-root` prints the resolved directory and its file count, and
|
|
277
280
|
`BANTAMKIT_ASSETS` overrides it. A build that cannot find the pack fails instead of shipping
|
|
278
|
-
without it.
|
|
281
|
+
without it — deliberately, because the silent version shipped once.
|
|
279
282
|
|
|
280
283
|
## The operator CLI: `python -m bantamkit.memory`
|
|
281
284
|
|
|
@@ -314,7 +317,7 @@ git clone https://github.com/Ink01101011/bantamkit
|
|
|
314
317
|
cd bantamkit
|
|
315
318
|
python -m venv .venv && .venv/bin/pip install -e "runtime-py[dev,mcp]"
|
|
316
319
|
.venv/bin/python -m pytest runtime-py/tests -q
|
|
317
|
-
.venv/bin/ruff check runtime-py
|
|
320
|
+
.venv/bin/ruff check runtime-py tools
|
|
318
321
|
```
|
|
319
322
|
|
|
320
323
|
The cross-runtime gate needs Node:
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "shiftwork_plan",
|
|
3
|
+
"description": "Shift-work plan: read-only batch view of a checkpoint — which units its `depends_on` graph permits to run in parallel. Answers `{\"result\": \"plan\", \"batches\", \"ready\", \"sequence\", \"width\", \"cursor\"}`: `ready` is `batches[0]`, the units dispatchable right now, and `width` is the largest batch length, the widest fan-out. Units with status `done` or `dropped` are satisfied — dropped from the graph, and edges pointing at them treated as already resolved; `todo`, `in_progress` and `blocked` stay in it. Every unit has priority 0, because the checkpoint schema has no priority field, so order inside a batch is `plan.units` order. Same refusal sentences as `work_plan` for a duplicate id, an unknown dependency or a cycle, and the same refusals `shiftwork_status` gives for a checkpoint it cannot read. It reports what the dependency graph permits; it does not move the cursor, which is echoed unchanged so the single-pointer contract and the batch view can be read side by side. An orchestrator stays responsible for what it actually dispatches: `depends_on` encodes logical order, not file contention. Never mutates.",
|
|
4
|
+
"surfaces": [
|
|
5
|
+
"mcp"
|
|
6
|
+
],
|
|
7
|
+
"parameters": {
|
|
8
|
+
"properties": {
|
|
9
|
+
"checkpoint": {
|
|
10
|
+
"title": "Checkpoint",
|
|
11
|
+
"type": "string"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"required": [
|
|
15
|
+
"checkpoint"
|
|
16
|
+
],
|
|
17
|
+
"type": "object",
|
|
18
|
+
"title": "shiftwork_planArguments"
|
|
19
|
+
},
|
|
20
|
+
"output_schema": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"additionalProperties": true,
|
|
23
|
+
"title": "shiftwork_planDictOutput"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "work_plan",
|
|
3
|
+
"description": "Work plan: turn a dependency graph into the batches that may run in parallel. Takes `nodes`, each `{id, depends_on, priority}` — `priority` defaults to 0 — and answers `{\"result\": \"plan\", \"batches\", \"sequence\", \"width\"}`: batch k holds every node whose dependencies all appear in batches below k, `sequence` is those batches flattened in order, and `width` is the largest batch length — the widest fan-out, which is the number an orchestrator needs to decide whether it can afford the batch. Order inside a batch is priority descending, then the order the nodes were given; both halves are contract, because determinism inside a batch is what two implementations are held to. Empty `nodes` is an ANSWER, not a refusal: no batches, no sequence, width 0. Three refusals, checked in this order and one sentence each: `duplicate node id <id>`, `node <id> depends on <dep>, which no node declares`, and `the graph has a cycle: <a> -> <b> -> <a>`. It reports what the graph permits and decides nothing about what may actually be dispatched together — `depends_on` encodes logical order, not file contention, so a batch this tool calls parallel may still hold work that writes one file. Pure computation over the nodes it was handed: it opens no file and takes no path. Never mutates.",
|
|
4
|
+
"surfaces": [
|
|
5
|
+
"mcp"
|
|
6
|
+
],
|
|
7
|
+
"parameters": {
|
|
8
|
+
"properties": {
|
|
9
|
+
"nodes": {
|
|
10
|
+
"title": "Nodes",
|
|
11
|
+
"type": "array",
|
|
12
|
+
"items": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"properties": {
|
|
15
|
+
"id": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"description": "The node's identifier, unique across `nodes`"
|
|
18
|
+
},
|
|
19
|
+
"depends_on": {
|
|
20
|
+
"type": "array",
|
|
21
|
+
"items": {
|
|
22
|
+
"type": "string"
|
|
23
|
+
},
|
|
24
|
+
"description": "Ids this node waits for; every one of them must be declared by some node"
|
|
25
|
+
},
|
|
26
|
+
"priority": {
|
|
27
|
+
"type": "integer",
|
|
28
|
+
"description": "Tie-break inside a batch, descending. Optional; 0 when absent"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"required": [
|
|
32
|
+
"id",
|
|
33
|
+
"depends_on"
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"required": [
|
|
39
|
+
"nodes"
|
|
40
|
+
],
|
|
41
|
+
"type": "object",
|
|
42
|
+
"title": "work_planArguments"
|
|
43
|
+
},
|
|
44
|
+
"output_schema": {
|
|
45
|
+
"type": "object",
|
|
46
|
+
"additionalProperties": true,
|
|
47
|
+
"title": "work_planDictOutput"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -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.
|
|
32
|
+
__version__ = "0.35.0"
|
|
@@ -30,11 +30,13 @@ 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.
|
|
33
|
+
validated output, never a query, never a document row. Nine of the fourteen tools take
|
|
34
34
|
an unbounded string (counted over `assets/tools/`: a `string` parameter with no `enum`
|
|
35
35
|
or `maxLength`, or an array of such; `bantamkit_read` and `repo_map` were two more until
|
|
36
|
-
job50 I5 retired them from the roster
|
|
37
|
-
|
|
36
|
+
job50 I5 retired them from the roster — and `work_plan` is NOT one of them: its `nodes`
|
|
37
|
+
is an array of objects, not an array of strings, so the rule does not reach the ids
|
|
38
|
+
inside it) and among those `skill_audit`'s `root`,
|
|
39
|
+
`token_ledger`'s `root` and `prices` and the four shift-work tools' `checkpoint` are
|
|
38
40
|
absolute paths; each record carries counts and tokens from a closed set, never the
|
|
39
41
|
path, never a part name, never a skill id, never a mapped file, never a session id,
|
|
40
42
|
never a model name. The dormant `bantamkit_read` and `repo_map` handlers keep the same
|
|
@@ -69,7 +71,7 @@ from datetime import UTC, datetime, timedelta
|
|
|
69
71
|
from pathlib import Path
|
|
70
72
|
from typing import Any
|
|
71
73
|
|
|
72
|
-
from bantamkit.memory.store import ensure_bantamkit_gitignore
|
|
74
|
+
from bantamkit.memory.store import bantamkit_dir_for, ensure_bantamkit_gitignore
|
|
73
75
|
|
|
74
76
|
#: Environment switch. Unset or `off`/`0`/`false`/`no`/empty -> disabled. `on`/`1`/
|
|
75
77
|
#: `true`/`yes` -> the default file inside the memory store. Anything else is taken as
|
|
@@ -289,11 +291,12 @@ class EventLog:
|
|
|
289
291
|
# USER RULING #2 (J51-8a): the ignore file is written only when THIS call is what
|
|
290
292
|
# creates `.bantamkit`, so existence has to be checked BEFORE the mkdir below --
|
|
291
293
|
# after it, the directory unconditionally exists and the question is unanswerable.
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
294
|
+
#
|
|
295
|
+
# J54-3: the walk moved into `bantamkit_dir_for` beside the writer it feeds, so the
|
|
296
|
+
# two creators in this runtime ask the same question in the same words rather than
|
|
297
|
+
# keeping a copy each. The answer here is unchanged -- a log file is never itself
|
|
298
|
+
# named `.bantamkit`, so self-or-ancestors and ancestors give the same directory.
|
|
299
|
+
bantamkit_dir = bantamkit_dir_for(self.path)
|
|
297
300
|
bantamkit_dir_existed_before = bantamkit_dir is not None and bantamkit_dir.exists()
|
|
298
301
|
self.path.parent.mkdir(parents=True, exist_ok=True)
|
|
299
302
|
if bantamkit_dir is not None:
|
|
@@ -30,6 +30,7 @@ from bantamkit import (
|
|
|
30
30
|
shiftwork,
|
|
31
31
|
skillaudit,
|
|
32
32
|
tokenledger,
|
|
33
|
+
workplan,
|
|
33
34
|
)
|
|
34
35
|
from bantamkit.assets import AssetNotFound, assets_root, load_skill, load_tool_asset
|
|
35
36
|
from bantamkit.client import BantamError
|
|
@@ -1474,6 +1475,24 @@ def build_server(memory: Memory, log: EventLog | None = None) -> Any:
|
|
|
1474
1475
|
_record_result(log, "shiftwork_status", lambda: shiftwork.status(checkpoint))
|
|
1475
1476
|
)
|
|
1476
1477
|
|
|
1478
|
+
def work_plan(nodes: list[dict[str, Any]]) -> dict[str, Any]:
|
|
1479
|
+
# `result` is added HERE and not in `workplan.plan`, which is Layer 1 and answers
|
|
1480
|
+
# the computation (`batches`, `sequence`, `width`) rather than a wire shape. The
|
|
1481
|
+
# wire shape is the tool asset's, so the verdict key is put on at the seam that
|
|
1482
|
+
# serves it — the same division `plan_batches` uses one layer down. A refusal
|
|
1483
|
+
# already carries its own `result` and passes through untouched, because
|
|
1484
|
+
# `_record_result` reads that key to write the register's verdict to the log.
|
|
1485
|
+
def answered() -> dict[str, Any]:
|
|
1486
|
+
plan = workplan.plan(nodes)
|
|
1487
|
+
return plan if plan.get("result") == "error" else {"result": "plan", **plan}
|
|
1488
|
+
|
|
1489
|
+
return _noted_dict(_record_result(log, "work_plan", answered))
|
|
1490
|
+
|
|
1491
|
+
def shiftwork_plan(checkpoint: str) -> dict[str, Any]:
|
|
1492
|
+
return _noted_dict(
|
|
1493
|
+
_record_result(log, "shiftwork_plan", lambda: shiftwork.plan_batches(checkpoint))
|
|
1494
|
+
)
|
|
1495
|
+
|
|
1477
1496
|
# A TOOL and not a resource or an `initialize` field, because the gap RB-P84 names is
|
|
1478
1497
|
# an AGENT MID-CALL: the host reads `serverInfo` once at handshake and the
|
|
1479
1498
|
# tool-calling model never sees it, and `resources/read` is a host-facing surface
|
|
@@ -1832,6 +1851,8 @@ def build_server(memory: Memory, log: EventLog | None = None) -> Any:
|
|
|
1832
1851
|
_from_manifest(skill_audit, "skill_audit"),
|
|
1833
1852
|
_from_manifest(memory_dream, "memory_dream"),
|
|
1834
1853
|
_from_manifest(token_ledger, "token_ledger"),
|
|
1854
|
+
_from_manifest(work_plan, "work_plan"),
|
|
1855
|
+
_from_manifest(shiftwork_plan, "shiftwork_plan"),
|
|
1835
1856
|
]
|
|
1836
1857
|
|
|
1837
1858
|
server = MCPServer(
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
`docs/memory.md` states, as a design decision, that `lint`, `archived` and
|
|
4
4
|
`restore` are **not** agent tools — "lifecycle is an operator decision, not a
|
|
5
|
-
model decision" — and the
|
|
5
|
+
model decision" — and the fourteen-tool surface holds to it; `compact` is the one
|
|
6
6
|
exception since job42 (`memory_compact`, the on-refusal path the model reaches
|
|
7
7
|
itself). That position is only coherent if the operator can actually make the
|
|
8
8
|
decision. Measured
|
|
@@ -286,6 +286,14 @@ def ensure_bantamkit_gitignore(directory: Path, *, created: bool) -> None:
|
|
|
286
286
|
would leave a `.bantamkit` that git can see (or ignore one it should not), which is
|
|
287
287
|
the whole bug this closes.
|
|
288
288
|
|
|
289
|
+
THE CREATORS, ENUMERATED (J54-3), because "anything else" is how one got missed: in
|
|
290
|
+
THIS runtime there are exactly two -- `MemoryStore._ensure_dirs` and `EventLog._append`
|
|
291
|
+
-- and both now ask `bantamkit_dir_for` which directory the decision is about, rather
|
|
292
|
+
than assuming the root's parent is it. `runtime-ts` has a THIRD, `hostinstall`'s
|
|
293
|
+
`thisCommand`, where npm creates `~/.bantamkit/mcp` for `--install`; there is no npm
|
|
294
|
+
install path in this runtime (the offline install is Node-only by user ruling), which
|
|
295
|
+
is why that creator has no counterpart here. `docs/porting.md` carries the row.
|
|
296
|
+
|
|
289
297
|
NEVER REWRITES. A `.gitignore` that already exists -- whatever its bytes -- is left
|
|
290
298
|
exactly as it is, kept as a second guard even when `created` is `True`: an operator
|
|
291
299
|
who deleted it to commit the directory keeps that decision, and this never diffs its
|
|
@@ -313,6 +321,34 @@ def ensure_bantamkit_gitignore(directory: Path, *, created: bool) -> None:
|
|
|
313
321
|
pass
|
|
314
322
|
|
|
315
323
|
|
|
324
|
+
def bantamkit_dir_for(path: Path) -> Path | None:
|
|
325
|
+
"""The `.bantamkit` directory a `mkdir(parents=True)` of `path` would create or fill,
|
|
326
|
+
or `None` when there is none: `path` itself if it is named `.bantamkit`, otherwise its
|
|
327
|
+
nearest ancestor that is.
|
|
328
|
+
|
|
329
|
+
WHY A WALK AND NOT `path.parent` (J54-3). Every creator has to hand
|
|
330
|
+
`ensure_bantamkit_gitignore` the directory the decision is ABOUT, and `parent` is the
|
|
331
|
+
right answer for exactly one shape of path, `<x>/.bantamkit/memory`. A store rooted AT
|
|
332
|
+
the `.bantamkit` directory (`--store ~/.bantamkit`) or nested deeper under it
|
|
333
|
+
(`<x>/.bantamkit/memory/extra`) creates a `.bantamkit` whose gitignore decision was
|
|
334
|
+
taken about the wrong directory -- so no decision was taken at all, and git could see
|
|
335
|
+
the whole tree. MEASURED, not hypothetical: `~/.bantamkit` on the machine this was
|
|
336
|
+
found on holds an empty `facts/` and `archive/` beside `memory/`, left by a store once
|
|
337
|
+
rooted at it, and no `.gitignore`.
|
|
338
|
+
|
|
339
|
+
NEAREST AND NOT OUTERMOST, which is the choice `EventLog._append` already made and this
|
|
340
|
+
function now carries for both creators: under a `<x>/.bantamkit/y/.bantamkit/z` the
|
|
341
|
+
directory a reader would expect to be ignored is the one the store is actually in.
|
|
342
|
+
|
|
343
|
+
READ-ONLY. It looks at names, never at the filesystem, so it is equally valid before or
|
|
344
|
+
after the mkdir -- but `created` is answered by checking THIS path's existence BEFORE.
|
|
345
|
+
"""
|
|
346
|
+
for candidate in (path, *path.parents):
|
|
347
|
+
if candidate.name == ".bantamkit":
|
|
348
|
+
return candidate
|
|
349
|
+
return None
|
|
350
|
+
|
|
351
|
+
|
|
316
352
|
class MemoryStore:
|
|
317
353
|
def __init__(
|
|
318
354
|
self,
|
|
@@ -405,8 +441,16 @@ class MemoryStore:
|
|
|
405
441
|
# Checked BEFORE the mkdir, per user ruling #2: this is the one moment that can
|
|
406
442
|
# tell whether `.bantamkit` already existed. After the mkdir it unconditionally
|
|
407
443
|
# exists either way, so the answer has to be captured now or not at all.
|
|
408
|
-
|
|
409
|
-
|
|
444
|
+
#
|
|
445
|
+
# J54-3: `bantamkit_dir_for`, not `self.root.parent`. The mkdir below is
|
|
446
|
+
# `parents=True`, so it creates every missing component of `self.root` -- a root
|
|
447
|
+
# that IS the `.bantamkit` directory, or one nested deeper under it, brought a
|
|
448
|
+
# `.bantamkit` into existence while the decision was being taken about some other
|
|
449
|
+
# directory, which meant no decision at all.
|
|
450
|
+
bantamkit_dir = bantamkit_dir_for(self.root)
|
|
451
|
+
bantamkit_dir_existed_before = (
|
|
452
|
+
bantamkit_dir is not None and bantamkit_dir.exists()
|
|
453
|
+
)
|
|
410
454
|
try:
|
|
411
455
|
(self.root / "facts").mkdir(parents=True, exist_ok=True)
|
|
412
456
|
(self.root / "archive").mkdir(parents=True, exist_ok=True)
|
|
@@ -415,7 +459,10 @@ class MemoryStore:
|
|
|
415
459
|
f"memory store could not be created: {self.root}; the directory is not"
|
|
416
460
|
" there and this filesystem would not make it, so nothing was written"
|
|
417
461
|
) from e
|
|
418
|
-
|
|
462
|
+
if bantamkit_dir is not None:
|
|
463
|
+
ensure_bantamkit_gitignore(
|
|
464
|
+
bantamkit_dir, created=not bantamkit_dir_existed_before
|
|
465
|
+
)
|
|
419
466
|
|
|
420
467
|
# ---- ops ----
|
|
421
468
|
|
|
@@ -67,7 +67,9 @@ a missing one.
|
|
|
67
67
|
|
|
68
68
|
Cursor advance is v1-linear: it moves to the first non-terminal unit in plan
|
|
69
69
|
order and ignores `depends_on` — non-linear plans need a planner unit to
|
|
70
|
-
reorder `plan.units` first.
|
|
70
|
+
reorder `plan.units` first. `plan_batches` below READS `depends_on` and answers
|
|
71
|
+
the batch view, so the module no longer ignores the field; what still ignores it
|
|
72
|
+
is CURSOR ADVANCE, and the batch view is read-only and moves nothing.
|
|
71
73
|
|
|
72
74
|
No lock: the MCP topology has one orchestrator by construction. The driver's
|
|
73
75
|
O_EXCL lock guards cross-process races this shape does not have, and clock-out
|
|
@@ -84,6 +86,7 @@ from typing import Any
|
|
|
84
86
|
|
|
85
87
|
import jsonschema
|
|
86
88
|
|
|
89
|
+
from bantamkit import workplan
|
|
87
90
|
from bantamkit.assets import AssetNotFound, load_schema, load_tool_asset
|
|
88
91
|
from bantamkit.contract import schema_error
|
|
89
92
|
|
|
@@ -550,3 +553,67 @@ def status(checkpoint: str) -> dict[str, Any]:
|
|
|
550
553
|
"open_questions": len(document["handoff"]["open_questions"]),
|
|
551
554
|
"last_history": history[-1] if history else None,
|
|
552
555
|
}
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
def plan_batches(checkpoint: str) -> dict[str, Any]:
|
|
559
|
+
"""Read-only batch view of a checkpoint. Never mutates.
|
|
560
|
+
|
|
561
|
+
The adapter over `workplan.plan`, and it holds no graph logic of its own: a loop over
|
|
562
|
+
`depends_on` here would be Layer 1's work done in Layer 5. Its whole content is the
|
|
563
|
+
three decisions below plus the shape it answers in.
|
|
564
|
+
|
|
565
|
+
**A `done` or `dropped` unit is SATISFIED**, which is two things and not one: it
|
|
566
|
+
leaves the graph, AND every edge pointing at it is treated as already resolved. Only
|
|
567
|
+
the first would be a defect rather than a simplification — `workplan.plan` refuses an
|
|
568
|
+
edge into an id no node declares, so dropping the unit while keeping the edge would
|
|
569
|
+
make every checkpoint with one finished unit unplannable, which is every checkpoint
|
|
570
|
+
after its first clock-out. `todo`, `in_progress` and `blocked` are all still work and
|
|
571
|
+
all stay in. The terminal pair is `TERMINAL_UNIT_STATUS`, the same constant the
|
|
572
|
+
driver's success test uses, so "finished" means one thing in this module.
|
|
573
|
+
|
|
574
|
+
**Every unit gets priority 0.** The checkpoint schema has no priority field and this
|
|
575
|
+
design does not add one, so the tie-break inside a batch falls through to the core's
|
|
576
|
+
insertion order — `plan.units` order, which is the order a reader of the checkpoint
|
|
577
|
+
already sees.
|
|
578
|
+
|
|
579
|
+
**The cursor is ECHOED, never written.** `clock_out` remains the only thing that
|
|
580
|
+
moves it and stays v1-linear; this tool reports what the graph PERMITS beside the
|
|
581
|
+
single pointer that says what the driver will actually do next, so an orchestrator
|
|
582
|
+
can read the two side by side and decide. Advisory, in one direction only.
|
|
583
|
+
|
|
584
|
+
Returns `{"result": "plan", "batches", "ready", "sequence", "width", "cursor"}` —
|
|
585
|
+
`ready` is `batches[0]`, or `[]` when the plan is all terminal, which is an ANSWER
|
|
586
|
+
and not a refusal. Refusals pass through verbatim in both directions: `_read_valid`'s
|
|
587
|
+
for a checkpoint that cannot be read or does not validate, and the core's own
|
|
588
|
+
duplicate-id / unknown-dependency / cycle sentences for a graph that cannot batch.
|
|
589
|
+
"""
|
|
590
|
+
document, refusal = _read_valid(Path(checkpoint))
|
|
591
|
+
if refusal is not None:
|
|
592
|
+
return refusal
|
|
593
|
+
nodes = [
|
|
594
|
+
# `depends_on` is required by the schema, so `_read_valid` has already refused a
|
|
595
|
+
# unit without it and the default below cannot fire here. It is written anyway
|
|
596
|
+
# because the Node adapter reaches the same mapping and MUST default it too: a
|
|
597
|
+
# default on one side only is how two runtimes come to disagree about real data.
|
|
598
|
+
{"id": unit["id"], "depends_on": list(unit.get("depends_on") or []), "priority": 0}
|
|
599
|
+
for unit in document["plan"]["units"]
|
|
600
|
+
if unit["status"] not in TERMINAL_UNIT_STATUS
|
|
601
|
+
]
|
|
602
|
+
satisfied = {
|
|
603
|
+
unit["id"] for unit in document["plan"]["units"] if unit["status"] in TERMINAL_UNIT_STATUS
|
|
604
|
+
}
|
|
605
|
+
for node in nodes:
|
|
606
|
+
node["depends_on"] = [dep for dep in node["depends_on"] if dep not in satisfied]
|
|
607
|
+
|
|
608
|
+
answer = workplan.plan(nodes)
|
|
609
|
+
if answer.get("result") == "error":
|
|
610
|
+
return answer
|
|
611
|
+
batches = answer["batches"]
|
|
612
|
+
return {
|
|
613
|
+
"result": "plan",
|
|
614
|
+
"batches": batches,
|
|
615
|
+
"ready": batches[0] if batches else [],
|
|
616
|
+
"sequence": answer["sequence"],
|
|
617
|
+
"width": answer["width"],
|
|
618
|
+
"cursor": document["plan"]["cursor"],
|
|
619
|
+
}
|