py-kodo 0.1.5__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.
- py_kodo-0.1.5/.gitignore +231 -0
- py_kodo-0.1.5/CLAUDE.md +226 -0
- py_kodo-0.1.5/DEPENDENCIES.md +133 -0
- py_kodo-0.1.5/DEVELOPMENT.md +85 -0
- py_kodo-0.1.5/LICENSE +201 -0
- py_kodo-0.1.5/PKG-INFO +363 -0
- py_kodo-0.1.5/README.md +145 -0
- py_kodo-0.1.5/build_number +1 -0
- py_kodo-0.1.5/doc/ADDING_A_SUBAGENT.md +110 -0
- py_kodo-0.1.5/doc/CHECKPOINTS.md +360 -0
- py_kodo-0.1.5/doc/INTERNALS.md +1201 -0
- py_kodo-0.1.5/doc/LLM_GATEWAY.md +77 -0
- py_kodo-0.1.5/doc/LLM_REGISTRY.md +991 -0
- py_kodo-0.1.5/doc/LOCAL_INFERENCE.md +184 -0
- py_kodo-0.1.5/doc/LOCAL_MODEL_MANAGER.md +676 -0
- py_kodo-0.1.5/doc/READ_WEBPAGE.md +180 -0
- py_kodo-0.1.5/doc/SECURITY.md +827 -0
- py_kodo-0.1.5/doc/SECURITY_RULES_GUIDE.md +456 -0
- py_kodo-0.1.5/doc/SECURITY_RULES_PLAN.md +799 -0
- py_kodo-0.1.5/doc/SESSIONS.md +586 -0
- py_kodo-0.1.5/doc/SETTINGS.md +132 -0
- py_kodo-0.1.5/doc/STATE_AND_LIFECYCLE.md +325 -0
- py_kodo-0.1.5/doc/STUCK_DETECTION.md +156 -0
- py_kodo-0.1.5/doc/TOOLS.md +688 -0
- py_kodo-0.1.5/doc/VALIDATOR.md +480 -0
- py_kodo-0.1.5/doc/WEB_SEARCH.md +292 -0
- py_kodo-0.1.5/doc/WS_PROTOCOL.md +1729 -0
- py_kodo-0.1.5/hatch_build.py +148 -0
- py_kodo-0.1.5/pyproject.toml +73 -0
- py_kodo-0.1.5/scripts/build.ps1 +10 -0
- py_kodo-0.1.5/scripts/build.sh +10 -0
- py_kodo-0.1.5/scripts/check_version.py +15 -0
- py_kodo-0.1.5/scripts/format.ps1 +10 -0
- py_kodo-0.1.5/scripts/format.sh +10 -0
- py_kodo-0.1.5/scripts/full_build.ps1 +20 -0
- py_kodo-0.1.5/scripts/full_build.sh +21 -0
- py_kodo-0.1.5/scripts/post_build.py +23 -0
- py_kodo-0.1.5/scripts/pre_build.py +66 -0
- py_kodo-0.1.5/scripts/static_analysis.ps1 +14 -0
- py_kodo-0.1.5/scripts/static_analysis.sh +13 -0
- py_kodo-0.1.5/scripts/test.ps1 +23 -0
- py_kodo-0.1.5/scripts/test.sh +23 -0
- py_kodo-0.1.5/src/kodo/__init__.py +5 -0
- py_kodo-0.1.5/src/kodo/__main__.py +12 -0
- py_kodo-0.1.5/src/kodo/binutils/__init__.py +25 -0
- py_kodo-0.1.5/src/kodo/binutils/_utils.py +377 -0
- py_kodo-0.1.5/src/kodo/common/__init__.py +15 -0
- py_kodo-0.1.5/src/kodo/common/_envelope.py +173 -0
- py_kodo-0.1.5/src/kodo/common/_protocols.py +72 -0
- py_kodo-0.1.5/src/kodo/common/_tempdir.py +44 -0
- py_kodo-0.1.5/src/kodo/common/py.typed +0 -0
- py_kodo-0.1.5/src/kodo/guided_state/__init__.py +44 -0
- py_kodo-0.1.5/src/kodo/guided_state/_paths.py +42 -0
- py_kodo-0.1.5/src/kodo/guided_state/_records.py +108 -0
- py_kodo-0.1.5/src/kodo/guided_state/_scan.py +40 -0
- py_kodo-0.1.5/src/kodo/guided_state/_store.py +143 -0
- py_kodo-0.1.5/src/kodo/guided_state/py.typed +0 -0
- py_kodo-0.1.5/src/kodo/llms/__init__.py +114 -0
- py_kodo-0.1.5/src/kodo/llms/_cloud_registry.py +153 -0
- py_kodo-0.1.5/src/kodo/llms/_context.py +54 -0
- py_kodo-0.1.5/src/kodo/llms/_gateway.py +295 -0
- py_kodo-0.1.5/src/kodo/llms/_hardware.py +150 -0
- py_kodo-0.1.5/src/kodo/llms/_interface.py +277 -0
- py_kodo-0.1.5/src/kodo/llms/_local_registry.py +2492 -0
- py_kodo-0.1.5/src/kodo/llms/_logger.py +185 -0
- py_kodo-0.1.5/src/kodo/llms/_sanitize.py +24 -0
- py_kodo-0.1.5/src/kodo/llms/_tool_logger.py +73 -0
- py_kodo-0.1.5/src/kodo/llms/anthropic/__init__.py +12 -0
- py_kodo-0.1.5/src/kodo/llms/anthropic/_cache.py +111 -0
- py_kodo-0.1.5/src/kodo/llms/anthropic/_claude.py +260 -0
- py_kodo-0.1.5/src/kodo/llms/anthropic/_retry.py +185 -0
- py_kodo-0.1.5/src/kodo/llms/anthropic/_usage.py +49 -0
- py_kodo-0.1.5/src/kodo/llms/anthropic/py.typed +0 -0
- py_kodo-0.1.5/src/kodo/llms/llamacpp/__init__.py +71 -0
- py_kodo-0.1.5/src/kodo/llms/llamacpp/_installer.py +519 -0
- py_kodo-0.1.5/src/kodo/llms/llamacpp/_llama.py +891 -0
- py_kodo-0.1.5/src/kodo/llms/llamacpp/_llama_server.py +474 -0
- py_kodo-0.1.5/src/kodo/llms/llamacpp/_manager.py +180 -0
- py_kodo-0.1.5/src/kodo/llms/llamacpp/py.typed +0 -0
- py_kodo-0.1.5/src/kodo/llms/local/__init__.py +41 -0
- py_kodo-0.1.5/src/kodo/llms/local/_hf.py +185 -0
- py_kodo-0.1.5/src/kodo/llms/local/_http.py +371 -0
- py_kodo-0.1.5/src/kodo/llms/local/_manager.py +772 -0
- py_kodo-0.1.5/src/kodo/llms/local/_state.py +129 -0
- py_kodo-0.1.5/src/kodo/llms/local/_types.py +166 -0
- py_kodo-0.1.5/src/kodo/llms/local/py.typed +0 -0
- py_kodo-0.1.5/src/kodo/llms/py.typed +0 -0
- py_kodo-0.1.5/src/kodo/mirror/__init__.py +24 -0
- py_kodo-0.1.5/src/kodo/mirror/_mirror.py +346 -0
- py_kodo-0.1.5/src/kodo/mirror/py.typed +0 -0
- py_kodo-0.1.5/src/kodo/project/__init__.py +25 -0
- py_kodo-0.1.5/src/kodo/project/_layout.py +363 -0
- py_kodo-0.1.5/src/kodo/project/_manifest.py +96 -0
- py_kodo-0.1.5/src/kodo/project/py.typed +0 -0
- py_kodo-0.1.5/src/kodo/py.typed +0 -0
- py_kodo-0.1.5/src/kodo/runtime/__init__.py +32 -0
- py_kodo-0.1.5/src/kodo/runtime/_attachments.py +202 -0
- py_kodo-0.1.5/src/kodo/runtime/_checkpoints.py +639 -0
- py_kodo-0.1.5/src/kodo/runtime/_cyclic_thinking.py +157 -0
- py_kodo-0.1.5/src/kodo/runtime/_engine/__init__.py +35 -0
- py_kodo-0.1.5/src/kodo/runtime/_engine/_checkpointing.py +308 -0
- py_kodo-0.1.5/src/kodo/runtime/_engine/_compaction.py +387 -0
- py_kodo-0.1.5/src/kodo/runtime/_engine/_core.py +1218 -0
- py_kodo-0.1.5/src/kodo/runtime/_engine/_events.py +377 -0
- py_kodo-0.1.5/src/kodo/runtime/_engine/_history.py +661 -0
- py_kodo-0.1.5/src/kodo/runtime/_engine/_llm.py +528 -0
- py_kodo-0.1.5/src/kodo/runtime/_engine/_proto.py +324 -0
- py_kodo-0.1.5/src/kodo/runtime/_engine/_resume.py +389 -0
- py_kodo-0.1.5/src/kodo/runtime/_engine/_services.py +127 -0
- py_kodo-0.1.5/src/kodo/runtime/_engine/_shared.py +148 -0
- py_kodo-0.1.5/src/kodo/runtime/_engine/_subagents.py +576 -0
- py_kodo-0.1.5/src/kodo/runtime/_engine/_titling.py +214 -0
- py_kodo-0.1.5/src/kodo/runtime/_engine/_turns.py +939 -0
- py_kodo-0.1.5/src/kodo/runtime/_engine/_watchdog.py +650 -0
- py_kodo-0.1.5/src/kodo/runtime/_engine/_worker.py +167 -0
- py_kodo-0.1.5/src/kodo/runtime/_gates.py +639 -0
- py_kodo-0.1.5/src/kodo/runtime/_security_rules.py +54 -0
- py_kodo-0.1.5/src/kodo/runtime/_session.py +157 -0
- py_kodo-0.1.5/src/kodo/runtime/_session_log.py +84 -0
- py_kodo-0.1.5/src/kodo/runtime/py.typed +0 -0
- py_kodo-0.1.5/src/kodo/security/__init__.py +68 -0
- py_kodo-0.1.5/src/kodo/security/_analysis.py +378 -0
- py_kodo-0.1.5/src/kodo/security/_classify.py +327 -0
- py_kodo-0.1.5/src/kodo/security/_defaults.py +617 -0
- py_kodo-0.1.5/src/kodo/security/_layer.py +353 -0
- py_kodo-0.1.5/src/kodo/security/_rules.py +835 -0
- py_kodo-0.1.5/src/kodo/security/_store.py +171 -0
- py_kodo-0.1.5/src/kodo/security/py.typed +0 -0
- py_kodo-0.1.5/src/kodo/server/__init__.py +21 -0
- py_kodo-0.1.5/src/kodo/server/__main__.py +79 -0
- py_kodo-0.1.5/src/kodo/server/_app.py +2041 -0
- py_kodo-0.1.5/src/kodo/server/_config.py +164 -0
- py_kodo-0.1.5/src/kodo/server/_connection_registry.py +194 -0
- py_kodo-0.1.5/src/kodo/server/_key_broker.py +92 -0
- py_kodo-0.1.5/src/kodo/server/_lifecycle.py +203 -0
- py_kodo-0.1.5/src/kodo/server/_session.py +37 -0
- py_kodo-0.1.5/src/kodo/server/_session_manager.py +588 -0
- py_kodo-0.1.5/src/kodo/server/py.typed +0 -0
- py_kodo-0.1.5/src/kodo/shellparser/__init__.py +23 -0
- py_kodo-0.1.5/src/kodo/shellparser/_parser.py +284 -0
- py_kodo-0.1.5/src/kodo/shellparser/_powershell.py +204 -0
- py_kodo-0.1.5/src/kodo/shellparser/py.typed +0 -0
- py_kodo-0.1.5/src/kodo/state/__init__.py +20 -0
- py_kodo-0.1.5/src/kodo/state/_toolcall_store.py +130 -0
- py_kodo-0.1.5/src/kodo/state/_transient.py +1254 -0
- py_kodo-0.1.5/src/kodo/state/py.typed +0 -0
- py_kodo-0.1.5/src/kodo/subagents/__init__.py +16 -0
- py_kodo-0.1.5/src/kodo/subagents/_loader.py +259 -0
- py_kodo-0.1.5/src/kodo/subagents/_registry.py +395 -0
- py_kodo-0.1.5/src/kodo/subagents/_subagentspec.py +51 -0
- py_kodo-0.1.5/src/kodo/subagents/agent_guide.md +313 -0
- py_kodo-0.1.5/src/kodo/subagents/agent_judge.md +85 -0
- py_kodo-0.1.5/src/kodo/subagents/agent_problem_solver.md +208 -0
- py_kodo-0.1.5/src/kodo/subagents/base_dependencies.md +102 -0
- py_kodo-0.1.5/src/kodo/subagents/base_toolchain.md +138 -0
- py_kodo-0.1.5/src/kodo/subagents/preamble_performance.md +85 -0
- py_kodo-0.1.5/src/kodo/subagents/preamble_security.md +43 -0
- py_kodo-0.1.5/src/kodo/subagents/py.typed +0 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/__init__.py +105 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_architect.py +33 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_architect_critic.py +27 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_code_critic.py +37 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_coder.py +23 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_compactor.py +33 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_developer.py +92 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_e2e_test_code_critic.py +46 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_e2e_test_coder.py +37 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_e2e_test_design_critic.py +32 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_e2e_test_designer.py +31 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_functional_design_critic.py +31 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_functional_designer.py +29 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_investigator.py +117 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_narrative_author.py +44 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_planner.py +98 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_requirements_author.py +27 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_requirements_critic.py +32 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_shapes.py +188 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_test_coder.py +30 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_test_design_critic.py +33 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_test_designer.py +21 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_toolchain_cpp.py +76 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_toolchain_depsmgr.py +103 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_toolchain_python.py +68 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_toolchain_rust.py +68 -0
- py_kodo-0.1.5/src/kodo/subagents/specs/_web_search_agent.py +96 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_architect.md +128 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_architect_critic.md +87 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_code_critic.md +101 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_coder.md +126 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_compactor.md +37 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_developer.md +97 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_e2e_test_code_critic.md +95 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_e2e_test_coder.md +94 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_e2e_test_design_critic.md +82 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_e2e_test_designer.md +123 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_functional_design_critic.md +97 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_functional_designer.md +173 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_investigator.md +73 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_narrative_author.md +181 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_planner.md +59 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_requirements_author.md +107 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_requirements_critic.md +82 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_test_coder.md +83 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_test_design_critic.md +91 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_test_designer.md +96 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_toolchain_cpp.md +84 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_toolchain_depsmgr.md +103 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_toolchain_python.md +73 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_toolchain_rust.md +73 -0
- py_kodo-0.1.5/src/kodo/subagents/subagent_web_search.md +94 -0
- py_kodo-0.1.5/src/kodo/titling/__init__.py +35 -0
- py_kodo-0.1.5/src/kodo/titling/_server.py +574 -0
- py_kodo-0.1.5/src/kodo/tools/__init__.py +131 -0
- py_kodo-0.1.5/src/kodo/tools/_ask_user.py +77 -0
- py_kodo-0.1.5/src/kodo/tools/_context.py +697 -0
- py_kodo-0.1.5/src/kodo/tools/_create_directory.py +39 -0
- py_kodo-0.1.5/src/kodo/tools/_create_file.py +59 -0
- py_kodo-0.1.5/src/kodo/tools/_create_new_project.py +62 -0
- py_kodo-0.1.5/src/kodo/tools/_disable_autonomous_mode.py +22 -0
- py_kodo-0.1.5/src/kodo/tools/_dispatch.py +572 -0
- py_kodo-0.1.5/src/kodo/tools/_document_feedback.py +59 -0
- py_kodo-0.1.5/src/kodo/tools/_edit_file.py +114 -0
- py_kodo-0.1.5/src/kodo/tools/_edit_review.py +40 -0
- py_kodo-0.1.5/src/kodo/tools/_escalate_blocker.py +40 -0
- py_kodo-0.1.5/src/kodo/tools/_filesystem.py +145 -0
- py_kodo-0.1.5/src/kodo/tools/_finalize_project.py +21 -0
- py_kodo-0.1.5/src/kodo/tools/_find_files.py +107 -0
- py_kodo-0.1.5/src/kodo/tools/_find_text_in_files.py +136 -0
- py_kodo-0.1.5/src/kodo/tools/_get_root_paths.py +43 -0
- py_kodo-0.1.5/src/kodo/tools/_get_web_search_state.py +25 -0
- py_kodo-0.1.5/src/kodo/tools/_guided_dev_status.py +29 -0
- py_kodo-0.1.5/src/kodo/tools/_init_project.py +53 -0
- py_kodo-0.1.5/src/kodo/tools/_paths.py +211 -0
- py_kodo-0.1.5/src/kodo/tools/_query_search_engine.py +121 -0
- py_kodo-0.1.5/src/kodo/tools/_read_attachment.py +47 -0
- py_kodo-0.1.5/src/kodo/tools/_read_file.py +164 -0
- py_kodo-0.1.5/src/kodo/tools/_read_webpage.py +151 -0
- py_kodo-0.1.5/src/kodo/tools/_remaining_time.py +26 -0
- py_kodo-0.1.5/src/kodo/tools/_return_result.py +50 -0
- py_kodo-0.1.5/src/kodo/tools/_rollback.py +35 -0
- py_kodo-0.1.5/src/kodo/tools/_run_author_critic_iteration.py +56 -0
- py_kodo-0.1.5/src/kodo/tools/_run_command.py +144 -0
- py_kodo-0.1.5/src/kodo/tools/_run_subagent.py +30 -0
- py_kodo-0.1.5/src/kodo/tools/_search.py +87 -0
- py_kodo-0.1.5/src/kodo/tools/_submit_evaluation.py +56 -0
- py_kodo-0.1.5/src/kodo/tools/_tool.py +69 -0
- py_kodo-0.1.5/src/kodo/tools/_toolchain_build.py +121 -0
- py_kodo-0.1.5/src/kodo/tools/_toolchain_deps.py +135 -0
- py_kodo-0.1.5/src/kodo/tools/_update_web_search_state.py +33 -0
- py_kodo-0.1.5/src/kodo/tools/_wait.py +33 -0
- py_kodo-0.1.5/src/kodo/tools/_web_search.py +75 -0
- py_kodo-0.1.5/src/kodo/toolspecs/__init__.py +155 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_ask_user.py +127 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_compliance.py +212 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_create_directory.py +102 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_create_file.py +182 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_create_new_project.py +99 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_disable_autonomous_mode.py +47 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_document_feedback.py +96 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_edit_file.py +198 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_escalate_blocker.py +109 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_filesystem.py +201 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_finalize_project.py +37 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_find_files.py +137 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_find_text_in_files.py +160 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_get_root_paths.py +113 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_get_web_search_state.py +56 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_guided_dev_status.py +72 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_init_project.py +96 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_intent.py +59 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_query_search_engine.py +103 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_read_attachment.py +60 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_read_file.py +154 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_read_webpage.py +124 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_remaining_time.py +49 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_return_result.py +59 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_rollback.py +57 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_run_author_critic_iteration.py +97 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_run_command.py +112 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_run_subagent.py +62 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_spec.py +117 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_submit_evaluation.py +78 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_toolchain_build.py +162 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_toolchain_deps.py +141 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_update_web_search_state.py +69 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_visibility.py +77 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_wait.py +63 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_web_search.py +135 -0
- py_kodo-0.1.5/src/kodo/toolspecs/_workspace.py +18 -0
- py_kodo-0.1.5/src/kodo/toolspecs/py.typed +0 -0
- py_kodo-0.1.5/src/kodo/transport/__init__.py +213 -0
- py_kodo-0.1.5/src/kodo/transport/_connection.py +226 -0
- py_kodo-0.1.5/src/kodo/transport/_messages.py +894 -0
- py_kodo-0.1.5/src/kodo/transport/_outbox.py +102 -0
- py_kodo-0.1.5/src/kodo/transport/_ws.py +195 -0
- py_kodo-0.1.5/src/kodo/transport/py.typed +0 -0
- py_kodo-0.1.5/src/kodo/validator/__init__.py +70 -0
- py_kodo-0.1.5/src/kodo/validator/__main__.py +329 -0
- py_kodo-0.1.5/src/kodo/validator/_client.py +458 -0
- py_kodo-0.1.5/src/kodo/validator/_evaluate.py +378 -0
- py_kodo-0.1.5/src/kodo/validator/_harness.py +471 -0
- py_kodo-0.1.5/src/kodo/validator/_home.py +136 -0
- py_kodo-0.1.5/src/kodo/validator/_models.py +229 -0
- py_kodo-0.1.5/src/kodo/validator/_scenario.py +242 -0
- py_kodo-0.1.5/src/kodo/validator/_server.py +202 -0
- py_kodo-0.1.5/src/kodo/validator/_transcript.py +247 -0
- py_kodo-0.1.5/src/kodo/validator/_user.py +204 -0
- py_kodo-0.1.5/src/kodo/validator/_vllm.py +353 -0
- py_kodo-0.1.5/src/kodo/validator/_workspace.py +170 -0
- py_kodo-0.1.5/src/kodo/validator/prompts/__init__.py +18 -0
- py_kodo-0.1.5/src/kodo/validator/prompts/_registry.py +108 -0
- py_kodo-0.1.5/src/kodo/validator/prompts/tictactoe/detailed_task.md +28 -0
- py_kodo-0.1.5/src/kodo/validator/prompts/tictactoe/rvp.md +62 -0
- py_kodo-0.1.5/src/kodo/validator/prompts/tictactoe/sparse_task.md +15 -0
- py_kodo-0.1.5/src/kodo/validator/prompts/tictactoe/upp.md +37 -0
- py_kodo-0.1.5/src/kodo/validator/scenarios/__init__.py +175 -0
- py_kodo-0.1.5/src/kodo/validator/scenarios/__main__.py +225 -0
- py_kodo-0.1.5/src/kodo/validator/scenarios/qwen35-9b/tictactoe_console.py +40 -0
- py_kodo-0.1.5/src/kodo/validator/scenarios/qwen36-27b/tictactoe_upp.py +40 -0
- py_kodo-0.1.5/src/kodo/websearch/__init__.py +63 -0
- py_kodo-0.1.5/src/kodo/websearch/_browser.py +306 -0
- py_kodo-0.1.5/src/kodo/websearch/_curlfetch.py +77 -0
- py_kodo-0.1.5/src/kodo/websearch/_enginequery.py +107 -0
- py_kodo-0.1.5/src/kodo/websearch/_engines.py +230 -0
- py_kodo-0.1.5/src/kodo/websearch/_engines_static.py +240 -0
- py_kodo-0.1.5/src/kodo/websearch/_htmlextract.py +307 -0
- py_kodo-0.1.5/src/kodo/websearch/_readpage.py +418 -0
- py_kodo-0.1.5/src/kodo/websearch/_state.py +129 -0
- py_kodo-0.1.5/src/kodo/websearch/_validate.py +71 -0
- py_kodo-0.1.5/test/__init__.py +0 -0
- py_kodo-0.1.5/test/test_agents.py +635 -0
- py_kodo-0.1.5/test/test_attachments.py +145 -0
- py_kodo-0.1.5/test/test_browser_session.py +275 -0
- py_kodo-0.1.5/test/test_cache.py +286 -0
- py_kodo-0.1.5/test/test_checkpoint_state.py +154 -0
- py_kodo-0.1.5/test/test_checkpoints.py +145 -0
- py_kodo-0.1.5/test/test_claude.py +564 -0
- py_kodo-0.1.5/test/test_common_tempdir.py +49 -0
- py_kodo-0.1.5/test/test_config.py +82 -0
- py_kodo-0.1.5/test/test_connection.py +212 -0
- py_kodo-0.1.5/test/test_connection_registry.py +115 -0
- py_kodo-0.1.5/test/test_create_new_project.py +49 -0
- py_kodo-0.1.5/test/test_cyclic_thinking.py +180 -0
- py_kodo-0.1.5/test/test_edit_review.py +407 -0
- py_kodo-0.1.5/test/test_engine_checkpointing.py +375 -0
- py_kodo-0.1.5/test/test_engine_compaction.py +430 -0
- py_kodo-0.1.5/test/test_engine_core.py +1712 -0
- py_kodo-0.1.5/test/test_engine_document_flow.py +314 -0
- py_kodo-0.1.5/test/test_engine_history.py +802 -0
- py_kodo-0.1.5/test/test_engine_llm.py +687 -0
- py_kodo-0.1.5/test/test_engine_resume.py +614 -0
- py_kodo-0.1.5/test/test_engine_shared_events.py +597 -0
- py_kodo-0.1.5/test/test_engine_stop.py +285 -0
- py_kodo-0.1.5/test/test_engine_subagents.py +565 -0
- py_kodo-0.1.5/test/test_engine_titling.py +324 -0
- py_kodo-0.1.5/test/test_engine_turns.py +1107 -0
- py_kodo-0.1.5/test/test_engine_watchdog.py +1192 -0
- py_kodo-0.1.5/test/test_engine_worker.py +475 -0
- py_kodo-0.1.5/test/test_enginequery.py +330 -0
- py_kodo-0.1.5/test/test_gates.py +744 -0
- py_kodo-0.1.5/test/test_guided_state.py +268 -0
- py_kodo-0.1.5/test/test_hardware.py +337 -0
- py_kodo-0.1.5/test/test_key_broker.py +141 -0
- py_kodo-0.1.5/test/test_lifecycle.py +152 -0
- py_kodo-0.1.5/test/test_llama_pure.py +1560 -0
- py_kodo-0.1.5/test/test_llama_server.py +119 -0
- py_kodo-0.1.5/test/test_llamacpp_installer.py +673 -0
- py_kodo-0.1.5/test/test_llm_flavors.py +796 -0
- py_kodo-0.1.5/test/test_llm_gateway.py +480 -0
- py_kodo-0.1.5/test/test_llm_logger.py +429 -0
- py_kodo-0.1.5/test/test_llms_local.py +590 -0
- py_kodo-0.1.5/test/test_manifest.py +114 -0
- py_kodo-0.1.5/test/test_readpage.py +313 -0
- py_kodo-0.1.5/test/test_resume_ledger.py +167 -0
- py_kodo-0.1.5/test/test_retry.py +380 -0
- py_kodo-0.1.5/test/test_sanitize.py +59 -0
- py_kodo-0.1.5/test/test_security_layer.py +622 -0
- py_kodo-0.1.5/test/test_security_path_store.py +82 -0
- py_kodo-0.1.5/test/test_security_rules.py +832 -0
- py_kodo-0.1.5/test/test_security_rules_module.py +188 -0
- py_kodo-0.1.5/test/test_security_store.py +62 -0
- py_kodo-0.1.5/test/test_server_integration.py +1099 -0
- py_kodo-0.1.5/test/test_session_log.py +136 -0
- py_kodo-0.1.5/test/test_session_manager.py +314 -0
- py_kodo-0.1.5/test/test_session_state.py +49 -0
- py_kodo-0.1.5/test/test_shadow_mirror.py +211 -0
- py_kodo-0.1.5/test/test_shellparser.py +195 -0
- py_kodo-0.1.5/test/test_subagentspecs.py +168 -0
- py_kodo-0.1.5/test/test_thinking_budget.py +192 -0
- py_kodo-0.1.5/test/test_thinking_stream_parser.py +43 -0
- py_kodo-0.1.5/test/test_titling.py +498 -0
- py_kodo-0.1.5/test/test_tools_compliance.py +1068 -0
- py_kodo-0.1.5/test/test_tools_guide.py +347 -0
- py_kodo-0.1.5/test/test_tools_leaf.py +1244 -0
- py_kodo-0.1.5/test/test_tools_paths.py +69 -0
- py_kodo-0.1.5/test/test_transient.py +726 -0
- py_kodo-0.1.5/test/test_transport.py +342 -0
- py_kodo-0.1.5/test/test_usage.py +108 -0
- py_kodo-0.1.5/test/test_validator.py +1030 -0
- py_kodo-0.1.5/test/test_validator_harness.py +333 -0
- py_kodo-0.1.5/test/test_validator_server.py +258 -0
- py_kodo-0.1.5/test/test_websearch.py +328 -0
py_kodo-0.1.5/.gitignore
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
.trash/
|
|
2
|
+
.claude/
|
|
3
|
+
.kodo/
|
|
4
|
+
uv.lock
|
|
5
|
+
.DS_Store
|
|
6
|
+
doc/hidden/
|
|
7
|
+
|
|
8
|
+
# mise
|
|
9
|
+
mise.toml
|
|
10
|
+
|
|
11
|
+
# Byte-compiled / optimized / DLL files
|
|
12
|
+
__pycache__/
|
|
13
|
+
*.py[codz]
|
|
14
|
+
*$py.class
|
|
15
|
+
|
|
16
|
+
# C extensions
|
|
17
|
+
*.so
|
|
18
|
+
|
|
19
|
+
# Distribution / packaging
|
|
20
|
+
.Python
|
|
21
|
+
build/
|
|
22
|
+
develop-eggs/
|
|
23
|
+
dist/
|
|
24
|
+
downloads/
|
|
25
|
+
eggs/
|
|
26
|
+
.eggs/
|
|
27
|
+
lib/
|
|
28
|
+
lib64/
|
|
29
|
+
parts/
|
|
30
|
+
sdist/
|
|
31
|
+
var/
|
|
32
|
+
wheels/
|
|
33
|
+
share/python-wheels/
|
|
34
|
+
*.egg-info/
|
|
35
|
+
.installed.cfg
|
|
36
|
+
*.egg
|
|
37
|
+
MANIFEST
|
|
38
|
+
|
|
39
|
+
# PyInstaller
|
|
40
|
+
# Usually these files are written by a python script from a template
|
|
41
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
42
|
+
*.manifest
|
|
43
|
+
*.spec
|
|
44
|
+
|
|
45
|
+
# Installer logs
|
|
46
|
+
pip-log.txt
|
|
47
|
+
pip-delete-this-directory.txt
|
|
48
|
+
|
|
49
|
+
# Unit test / coverage reports
|
|
50
|
+
htmlcov/
|
|
51
|
+
.tox/
|
|
52
|
+
.nox/
|
|
53
|
+
.coverage
|
|
54
|
+
.coverage.*
|
|
55
|
+
.cache
|
|
56
|
+
nosetests.xml
|
|
57
|
+
coverage.xml
|
|
58
|
+
*.cover
|
|
59
|
+
*.py.cover
|
|
60
|
+
*.lcov
|
|
61
|
+
.hypothesis/
|
|
62
|
+
.pytest_cache/
|
|
63
|
+
cover/
|
|
64
|
+
|
|
65
|
+
# Translations
|
|
66
|
+
*.mo
|
|
67
|
+
*.pot
|
|
68
|
+
|
|
69
|
+
# Django stuff:
|
|
70
|
+
*.log
|
|
71
|
+
local_settings.py
|
|
72
|
+
db.sqlite3
|
|
73
|
+
db.sqlite3-journal
|
|
74
|
+
|
|
75
|
+
# Flask stuff:
|
|
76
|
+
instance/
|
|
77
|
+
.webassets-cache
|
|
78
|
+
|
|
79
|
+
# Scrapy stuff:
|
|
80
|
+
.scrapy
|
|
81
|
+
|
|
82
|
+
# Sphinx documentation
|
|
83
|
+
docs/_build/
|
|
84
|
+
|
|
85
|
+
# PyBuilder
|
|
86
|
+
.pybuilder/
|
|
87
|
+
target/
|
|
88
|
+
|
|
89
|
+
# Jupyter Notebook
|
|
90
|
+
*.ipynb
|
|
91
|
+
.ipynb_checkpoints
|
|
92
|
+
|
|
93
|
+
# IPython
|
|
94
|
+
profile_default/
|
|
95
|
+
ipython_config.py
|
|
96
|
+
|
|
97
|
+
# pyenv
|
|
98
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
99
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
100
|
+
# .python-version
|
|
101
|
+
|
|
102
|
+
# pipenv
|
|
103
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
104
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
105
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
106
|
+
# install all needed dependencies.
|
|
107
|
+
# Pipfile.lock
|
|
108
|
+
|
|
109
|
+
# UV
|
|
110
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
111
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
112
|
+
# commonly ignored for libraries.
|
|
113
|
+
# uv.lock
|
|
114
|
+
|
|
115
|
+
# poetry
|
|
116
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
117
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
118
|
+
# commonly ignored for libraries.
|
|
119
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
120
|
+
# poetry.lock
|
|
121
|
+
# poetry.toml
|
|
122
|
+
|
|
123
|
+
# pdm
|
|
124
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
125
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
126
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
127
|
+
# pdm.lock
|
|
128
|
+
# pdm.toml
|
|
129
|
+
.pdm-python
|
|
130
|
+
.pdm-build/
|
|
131
|
+
|
|
132
|
+
# pixi
|
|
133
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
134
|
+
# pixi.lock
|
|
135
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
136
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
137
|
+
.pixi/*
|
|
138
|
+
!.pixi/config.toml
|
|
139
|
+
|
|
140
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
141
|
+
__pypackages__/
|
|
142
|
+
|
|
143
|
+
# Celery stuff
|
|
144
|
+
celerybeat-schedule*
|
|
145
|
+
celerybeat.pid
|
|
146
|
+
|
|
147
|
+
# Redis
|
|
148
|
+
*.rdb
|
|
149
|
+
*.aof
|
|
150
|
+
*.pid
|
|
151
|
+
|
|
152
|
+
# RabbitMQ
|
|
153
|
+
mnesia/
|
|
154
|
+
rabbitmq/
|
|
155
|
+
rabbitmq-data/
|
|
156
|
+
|
|
157
|
+
# ActiveMQ
|
|
158
|
+
activemq-data/
|
|
159
|
+
|
|
160
|
+
# SageMath parsed files
|
|
161
|
+
*.sage.py
|
|
162
|
+
|
|
163
|
+
# Environments
|
|
164
|
+
.env
|
|
165
|
+
.envrc
|
|
166
|
+
.venv
|
|
167
|
+
env/
|
|
168
|
+
venv/
|
|
169
|
+
ENV/
|
|
170
|
+
env.bak/
|
|
171
|
+
venv.bak/
|
|
172
|
+
|
|
173
|
+
# Spyder project settings
|
|
174
|
+
.spyderproject
|
|
175
|
+
.spyproject
|
|
176
|
+
|
|
177
|
+
# Rope project settings
|
|
178
|
+
.ropeproject
|
|
179
|
+
|
|
180
|
+
# mkdocs documentation
|
|
181
|
+
/site
|
|
182
|
+
|
|
183
|
+
# mypy
|
|
184
|
+
.mypy_cache/
|
|
185
|
+
.dmypy.json
|
|
186
|
+
dmypy.json
|
|
187
|
+
|
|
188
|
+
# Pyre type checker
|
|
189
|
+
.pyre/
|
|
190
|
+
|
|
191
|
+
# pytype static type analyzer
|
|
192
|
+
.pytype/
|
|
193
|
+
|
|
194
|
+
# Cython debug symbols
|
|
195
|
+
cython_debug/
|
|
196
|
+
|
|
197
|
+
# PyCharm
|
|
198
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
199
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
200
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
201
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
202
|
+
# .idea/
|
|
203
|
+
|
|
204
|
+
# Abstra
|
|
205
|
+
# Abstra is an AI-powered process automation framework.
|
|
206
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
207
|
+
# Learn more at https://abstra.io/docs
|
|
208
|
+
.abstra/
|
|
209
|
+
|
|
210
|
+
# Visual Studio Code
|
|
211
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
212
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
213
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
214
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
215
|
+
# .vscode/
|
|
216
|
+
# Temporary file for partial code execution
|
|
217
|
+
tempCodeRunnerFile.py
|
|
218
|
+
|
|
219
|
+
# Ruff stuff:
|
|
220
|
+
.ruff_cache/
|
|
221
|
+
|
|
222
|
+
# PyPI configuration file
|
|
223
|
+
.pypirc
|
|
224
|
+
|
|
225
|
+
# Marimo
|
|
226
|
+
marimo/_static/
|
|
227
|
+
marimo/_lsp/
|
|
228
|
+
__marimo__/
|
|
229
|
+
|
|
230
|
+
# Streamlit
|
|
231
|
+
.streamlit/secrets.toml
|
py_kodo-0.1.5/CLAUDE.md
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# This file contains general coding guidelines for Claude Code
|
|
2
|
+
|
|
3
|
+
## Class definition
|
|
4
|
+
|
|
5
|
+
Always model a class by splitting it into private and public members. Public members can be properties and methods, private members can be variables and methods.
|
|
6
|
+
|
|
7
|
+
Always name-mangle private members of a class. If necessary, provide access to private member variables through read-only properties. You MUST avoid implementation of member variables that need to be modified outside of the class as this is indicative of bad design/architecture.
|
|
8
|
+
|
|
9
|
+
Never use name-mangled symbols from outside the class.
|
|
10
|
+
|
|
11
|
+
Add Google Style docstrings to `__init__()`, public methods, and the class itself.
|
|
12
|
+
|
|
13
|
+
Example:
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
class Example:
|
|
17
|
+
"""This is an example of class definition."""
|
|
18
|
+
__var1: int
|
|
19
|
+
__var2: str
|
|
20
|
+
|
|
21
|
+
def __init__(self, var1: int) -> None:
|
|
22
|
+
"""Docstring for constructor
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
var1 (int): bla bla bla
|
|
26
|
+
"""
|
|
27
|
+
self.__var1 = var1
|
|
28
|
+
self.__var2 = str(var1 + 1)
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def var1(self) -> int:
|
|
32
|
+
return self.__var1
|
|
33
|
+
|
|
34
|
+
def method(self, arg: str) -> str:
|
|
35
|
+
"""Docstring for method
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
var1 (int): bla bla bla
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
str: bla bla bla
|
|
42
|
+
|
|
43
|
+
"""
|
|
44
|
+
return self.__var2 + arg
|
|
45
|
+
|
|
46
|
+
def __private_method(self) -> None:
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Module definition
|
|
52
|
+
|
|
53
|
+
Always create __init__.py and py.typed in every python module. Always use relative imports from files within the module. Never use relative imports when importing from other packages.
|
|
54
|
+
|
|
55
|
+
Always prepend underscore to python files inside a package.
|
|
56
|
+
|
|
57
|
+
Always define `__all__` in `__init__.py`
|
|
58
|
+
|
|
59
|
+
Always put ```from __future__ import annotations``` at the top of each python source code file except for `__init__.py` files.
|
|
60
|
+
|
|
61
|
+
Always provide a Google Style docstring for a module.
|
|
62
|
+
|
|
63
|
+
Never use star import: ```from somewhere import * # Never do that!```
|
|
64
|
+
|
|
65
|
+
Example:
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
"""This is an example module"""
|
|
69
|
+
|
|
70
|
+
from ._local_file import Something
|
|
71
|
+
from another_package.subpackage import Other
|
|
72
|
+
|
|
73
|
+
__all__ = [
|
|
74
|
+
'Something',
|
|
75
|
+
'Other',
|
|
76
|
+
]
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Imports
|
|
80
|
+
|
|
81
|
+
You MUST NOT use star imports. This is not allowed: `from module import *`.
|
|
82
|
+
|
|
83
|
+
You MUST NOT import from python files. You MUST ALWAYS import from modules (packages). This is not allowed: `from module.submodule._file import MyClass`.
|
|
84
|
+
|
|
85
|
+
Instead, export the public name from the package's `__init__.py` (add it to `__init__` and `__all__`) and import it from the package: `from module.submodule import MyClass`. If a name needs to be used outside its package, it MUST be part of that package's public API — promote a private `_helper` to a public name rather than reaching into the `_file` from another package. The only relative `from ._file import X` imports allowed are those a package makes about its own sibling modules (e.g. inside its `__init__.py`); consumers in other packages MUST go through the package's public surface. Tests follow the same rule.
|
|
86
|
+
|
|
87
|
+
### Layering: `kodo.tools`
|
|
88
|
+
|
|
89
|
+
`kodo.tools` (the dispatch implementation of every tool in `kodo.toolspecs`) is a dedicated import tier __between__ `toolspecs` (T2) and `subagents`/`llms` (T3). It MUST import only from T0/T1/T2 — in practice `guided_state` + `project` + `toolspecs` — and MUST NEVER import `subagents`, `llms`, or `runtime`. Collaborators from higher tiers (the gate, the session, every engine-side operation) are expressed as structural Protocols inside `kodo.tools` (`GateLike`, `SessionLike`, `EngineServices`) and injected by `runtime`. There is one unified tool surface: every agent (guide included) gets exactly the tools its frontmatter declares, dispatched through a single `ToolDispatcher`. Each tool is a `Tool` subclass (the ABC in `tools/_tool.py`) in its own `tools/_<tool_name>.py` module; its constructor binds the run's `ToolContext` and `handle(self, tool_input)` reads it via the `context` property. The `_TOOL_CLASSES` table in `tools/_dispatch.py` is the single spec→class binding. Verify the ceiling with `grep -rE "^\s*(from|import) kodo\.(subagents|llms|runtime|server)" src/kodo/tools` (must be empty).
|
|
90
|
+
|
|
91
|
+
## Type hints
|
|
92
|
+
|
|
93
|
+
You MUST NOT use `Optional`, `Any`, `Dict`, `List`, `TYPE_CHECKING` etc. No loose type safety, no outdated classes.
|
|
94
|
+
|
|
95
|
+
You MUST use `object` instead of `Any`, and use `cast` or `isinstance` where necessary.
|
|
96
|
+
|
|
97
|
+
One exception for the "no Any" rule: you are ALLOWED to use `Any` in definitions of kwargs, as this is the only way to make it work.
|
|
98
|
+
|
|
99
|
+
You MUST use `typename | None` instead of `Optional`.
|
|
100
|
+
|
|
101
|
+
## Windows-specific pitfalls
|
|
102
|
+
|
|
103
|
+
### `os.kill(pid, 0)` fires a real Ctrl+C on Windows
|
|
104
|
+
|
|
105
|
+
On Unix, `os.kill(pid, 0)` is the standard idiom for checking whether a process is alive: signal 0 is never delivered, it just probes for the process.
|
|
106
|
+
|
|
107
|
+
On Windows the semantics are completely different. Python maps `os.kill` to `GenerateConsoleCtrlEvent` for `CTRL_C_EVENT` and `CTRL_BREAK_EVENT`, and to `TerminateProcess` for `SIGTERM`. Critically, `signal.CTRL_C_EVENT == 0`, so `os.kill(pid, 0)` is identical to `os.kill(pid, signal.CTRL_C_EVENT)`. This calls `GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid)`, which broadcasts a real Ctrl+C event to every process sharing the current console session. Python's console control handler receives it, calls `PyErr_SetInterrupt()`, and the interrupt flag sits armed. The call returns True (success), so the caller never sees an exception — the damage is invisible. The queued interrupt fires later, at the next I/O checkpoint inside any `read()` or `write()` call, raising `KeyboardInterrupt` in an apparently unrelated location.
|
|
108
|
+
|
|
109
|
+
__Rule:__ Never use `os.kill(pid, 0)` to check process liveness. On Windows use `ctypes.windll.kernel32.OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, pid)` instead: a non-NULL return value means the process exists; no signal is sent.
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
@staticmethod
|
|
113
|
+
def __is_running(pid: int) -> bool:
|
|
114
|
+
if sys.platform == "win32":
|
|
115
|
+
import ctypes
|
|
116
|
+
_PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
|
|
117
|
+
handle = ctypes.windll.kernel32.OpenProcess(
|
|
118
|
+
_PROCESS_QUERY_LIMITED_INFORMATION, False, pid
|
|
119
|
+
)
|
|
120
|
+
if handle:
|
|
121
|
+
ctypes.windll.kernel32.CloseHandle(handle)
|
|
122
|
+
return True
|
|
123
|
+
return False
|
|
124
|
+
try:
|
|
125
|
+
os.kill(pid, 0)
|
|
126
|
+
return True
|
|
127
|
+
except OSError:
|
|
128
|
+
return False
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Signal-handler tests must not touch the real signal table
|
|
132
|
+
|
|
133
|
+
Tests that exercise `signal.signal()`-based code (e.g. `install_signal_handlers`) must mock `signal.signal` via `monkeypatch` rather than calling the real function. The real function changes the process-wide signal table for the entire pytest session. On Windows, replacing the `SIGINT` handler removes asyncio's Ctrl+C wakeup path, causing async tests that run after the signal-handler tests to hang indefinitely inside `asyncio.to_thread` or similar I/O waits.
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
def test_install_signal_handlers_sets_shutdown_requested(
|
|
137
|
+
lifecycle: Lifecycle,
|
|
138
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
139
|
+
) -> None:
|
|
140
|
+
installed: dict[int, object] = {}
|
|
141
|
+
monkeypatch.setattr(signal, "signal", lambda signum, h: installed.update({signum: h}))
|
|
142
|
+
|
|
143
|
+
lifecycle.install_signal_handlers(lambda: None)
|
|
144
|
+
|
|
145
|
+
handler = installed.get(signal.SIGTERM)
|
|
146
|
+
assert callable(handler)
|
|
147
|
+
handler(signal.SIGTERM, None) # type: ignore[operator]
|
|
148
|
+
assert lifecycle.shutdown_requested is True
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
`monkeypatch` is automatically undone after each test with no global side-effects.
|
|
152
|
+
|
|
153
|
+
## Test implementation
|
|
154
|
+
|
|
155
|
+
Design tests and classes such that unit tests validate behavior, not implementation details. It should not matter how many times a mock was called if the behavior is correct.
|
|
156
|
+
|
|
157
|
+
Never build tests that rely on private methods or variables.
|
|
158
|
+
|
|
159
|
+
Test private methods through behavoir of public methods.
|
|
160
|
+
|
|
161
|
+
## Prompts
|
|
162
|
+
|
|
163
|
+
When user asks you to review, edit, or generate an LLM prompt, you MUST follow these rules.
|
|
164
|
+
|
|
165
|
+
### Drafting style
|
|
166
|
+
|
|
167
|
+
You MUST generate the prompt in a way that minimizes hallucinations. Require the sub-agent to quote source material when it cites it, and to reference identifiers (requirement IDs, codenames, test IDs, file paths with line numbers) by their exact value rather than paraphrasing.
|
|
168
|
+
|
|
169
|
+
You MUST be specific. You MUST NOT use vague qualifiers such as "almost", "possibly", "maybe", "appropriate", "reasonable", "as needed", "may", "could", or "should consider". Replace each with a definite statement of the rule or with a measurable threshold.
|
|
170
|
+
|
|
171
|
+
You MUST state the sub-agent's purpose in a single sentence at the top of the prompt, immediately after the agent's name. The prompt MUST keep the sub-agent on that single purpose. Any behavior that falls outside the stated purpose is to be explicitly excluded under "What to Avoid".
|
|
172
|
+
|
|
173
|
+
### Inputs, outputs, and reporting contract
|
|
174
|
+
|
|
175
|
+
Every sub-agent MUST have three things defined in its prompt:
|
|
176
|
+
|
|
177
|
+
1. __The prompt__ — the system prompt itself, including purpose, inputs, workflow, output structure, and exclusions.
|
|
178
|
+
2. __The task__ — the per-invocation user message the engine sends, carrying the input file paths and inline content the agent reads as input.
|
|
179
|
+
3. __The reporting tools__ — `filesystem`/`edit_file`/`create_file`/`read_file` for authors, `read_file`/`document_feedback` for critics, and, where applicable, the user-dialog and escalation tools. Tool names are named in the prompt; their JSON schemas live in code. The prompt MUST NOT restate any schema, so the prompt and the schema cannot drift.
|
|
180
|
+
|
|
181
|
+
Authoritative locations:
|
|
182
|
+
|
|
183
|
+
- The agent-facing tool catalog — internal/external names, descriptions, autonomous-mode behavior, and when-to-use guidance for every tool — lives in each tool's `ToolSpec` under [src/kodo/toolspecs/](src/kodo/toolspecs/) (`external_name`, `user_description`, `description`, `autonomous_mode`, `when_to_use`), rendered into the `## Tools` section of every agent prompt by [src/kodo/subagents/_registry.py](src/kodo/subagents/_registry.py). Prompts name tools; they never restate schemas.
|
|
184
|
+
- `filesystem`, `edit_file`, `create_file`, `read_file` — `ToolSpec`s in [src/kodo/toolspecs/](src/kodo/toolspecs/), dispatched in-process by their `Tool` subclasses in [src/kodo/tools/](src/kodo/tools/) (`FilesystemTool`, `EditFileTool`, `CreateFileTool`, `ReadFileTool`).
|
|
185
|
+
- `escalate_blocker`, `ask_user`, `document_feedback` — `ToolSpec`s in [src/kodo/toolspecs/](src/kodo/toolspecs/), one module per tool (`_escalate_blocker.py`, `_ask_user.py`, `_document_feedback.py`).
|
|
186
|
+
|
|
187
|
+
The agent's frontmatter `tools:` list MUST include every tool the agent calls.
|
|
188
|
+
|
|
189
|
+
### File-native document contract (replaces the former artifact workspace)
|
|
190
|
+
|
|
191
|
+
Sub-agents read and write the project's __real files__ directly under `specs/`, `src/`, and `test/` — there is no staging area, no artifact index, and no toolchain-driven file naming. Every document's revision/review history is tracked separately, as a per-file, append-only `.jsonl` evolution log (`kodo.guided_state`; see [STATE_AND_LIFECYCLE.md §1](../../doc/STATE_AND_LIFECYCLE.md)) — agents never read or write that log directly, it is produced entirely by the engine and the `document_feedback` tool.
|
|
192
|
+
|
|
193
|
+
- __Production__ — authors write a new document with `create_file`, choosing their own path under `specs/`, `src/`, or `test/` (no fixed naming convention — match the project's existing structure). There is no separate "I'm done" tool call; the engine records a `new_revision` entry in that file's evolution log automatically, right after the mirror commit lands.
|
|
194
|
+
- __Revisions__ — an author addressing critic or user feedback edits the __same file in place__ with `edit_file` (a string-match edit; pass the whole new content as `new_string` to regenerate a file end to end). There is no `supersedes` chain to maintain — the jsonl log is the revision history.
|
|
195
|
+
- __Review__ — a critic calls `document_feedback(path, accept, concerns?, summary?)` exactly once per file reviewed: `accept: false` with a non-empty `concerns` array to reject, `accept: true` with empty `concerns` to accept. This is the __only__ output a critic produces — it never edits the file itself, and it never decides what happens next.
|
|
196
|
+
- __Acceptance — engine-owned, not agent-owned__. After a `document_feedback(accept: true)` call, the engine alone drives what happens: autonomous mode immediately marks the file accepted; interactive mode presents it to the user and records their decision. No sub-agent ever fires a review gate or reports completion itself — those tools (`request_user_review_artifact`, `report_artifact_completed`) were removed along with the artifact workspace.
|
|
197
|
+
- __Reading inputs__ — when the engine has not already injected an input document's content into the task message, agents call `read_file` (whole file, specific line ranges, or a regex `pattern` with context lines).
|
|
198
|
+
- __Cross-agent routings__ — when one author challenges another author's file (e.g. Coder suspects a test file Test Coder wrote is wrong), the challenger calls `document_feedback` on that file directly, with concerns in its own vocabulary (e.g. `suspected_test_bug`, `spec_ambiguity`). The engine routes it to the file's usual reviewer loop. There is no separate "routing" tool.
|
|
199
|
+
|
|
200
|
+
### No free-form output
|
|
201
|
+
|
|
202
|
+
A sub-agent MUST NOT use free-form text for any output the harness has to interpret or that is delivered to the user. Specifically:
|
|
203
|
+
|
|
204
|
+
- __Verdicts__ — every verdict is a `document_feedback(path, accept, concerns)` call. Critics MUST NOT signal accept/revise via prose or via convention substrings.
|
|
205
|
+
- __Completion__ — production is a `create_file`/`edit_file` call; acceptance is driven entirely by the engine after a critic's `document_feedback(accept: true)` call — no sub-agent reports completion itself.
|
|
206
|
+
- __Cross-agent routings__ — every routing is a `document_feedback(path, accept=false, concerns=[...])` call targeting the challenged file. Routings MUST NOT be expressed as embedded prose or markdown blocks.
|
|
207
|
+
- __Escalations to the user__ — when an author cannot defensibly make a call (an iteration cap is reached, or a back-and-forth cannot be reconciled), it calls `escalate_blocker` with a structured `reason`, `summary`, and `blocking_paths` array. This relinquishes the decision to the guide; it is an author/coder-side tool, never held by critics.
|
|
208
|
+
- __User dialog__ — agents reach the user only through the common dialog tools, never free-form. `ask_user` elicits or validates a single piece of user-supplied information the agent then acts on itself (used by Narrative Author and by critics gap-filling against user input); the document-review gate is engine-driven, not a sub-agent tool. Which agents hold which tool is set by each agent's frontmatter; `ask_user` is withheld entirely in autonomous mode (no answer to synthesize), and the document-review gate auto-accepts.
|
|
209
|
+
|
|
210
|
+
Intermediate reasoning text the agent emits between tool calls is allowed but unused; the harness ignores it. Sub-agent prompts SHOULD direct the agent to be terse in such text.
|
|
211
|
+
|
|
212
|
+
### Transport-agnostic tool contract
|
|
213
|
+
|
|
214
|
+
Every tool a sub-agent calls MUST be defined as a `ToolSpec` with a JSON Schema in [src/kodo/toolspecs/](src/kodo/toolspecs/), one module per tool. Each tool's dispatch is implemented in [src/kodo/tools/](src/kodo/tools/) — one `Tool` subclass per `_<tool_name>.py` module, routed through a single `ToolDispatcher` the engine builds per agent run (guide and leaf alike). `kodo.tools` is a dedicated import tier between `toolspecs` and `subagents`/`llms`: it may import only `guided_state` + `project` + `toolspecs`, and the gate/session/engine-services it needs are injected via structural Protocols. External MCP tool support is planned post-MVP. The sub-agent prompt MUST name the tool but MUST NOT restate the schema, so prompts remain valid when the transport changes.
|
|
215
|
+
|
|
216
|
+
### Authoring a new sub-agent prompt — checklist
|
|
217
|
+
|
|
218
|
+
When adding or revising a sub-agent prompt, the prompt MUST contain, in this order:
|
|
219
|
+
|
|
220
|
+
1. The agent's name (one line, bold) and a one-sentence purpose statement.
|
|
221
|
+
2. __Inputs__ — what the agent reads, by name and source.
|
|
222
|
+
3. __Workflow__ — numbered stages or phases, each with concrete actions and stop conditions.
|
|
223
|
+
4. __Reporting__ — names of the tools the agent calls, what each one signals, and the order in which they are called over the agent's lifetime. References the tool name only; never restates the schema.
|
|
224
|
+
5. __What to Avoid__ — explicit exclusions, including a line that prohibits free-form output for any of the contracts covered by a reporting tool.
|
|
225
|
+
|
|
226
|
+
The frontmatter MUST list every tool the agent calls, including reporting tools.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Dependencies
|
|
2
|
+
|
|
3
|
+
## Manager
|
|
4
|
+
|
|
5
|
+
- **Manager** — hatch 1.17 (at `~/.local/bin/hatch`).
|
|
6
|
+
- **Manifest** — `pyproject.toml` (PEP 621 project table + hatch env configuration).
|
|
7
|
+
- **Lockfile** — none. Hatch resolves dependencies on-the-fly when the environment is (re)created; there is no lockfile to maintain.
|
|
8
|
+
|
|
9
|
+
## Kinds
|
|
10
|
+
|
|
11
|
+
| Kind | Manifest location |
|
|
12
|
+
| -------- | ------------------------------------------ |
|
|
13
|
+
| runtime | `[project].dependencies` |
|
|
14
|
+
| dev | `[tool.hatch.envs.default].dependencies` |
|
|
15
|
+
| build | `[build-system].requires` |
|
|
16
|
+
|
|
17
|
+
## Operations
|
|
18
|
+
|
|
19
|
+
### runtime
|
|
20
|
+
|
|
21
|
+
**Add**
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
hatch project add <pkg>
|
|
25
|
+
# Pinned to a specific version:
|
|
26
|
+
hatch project add <pkg>==<version>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Appends `<pkg>` (or `<pkg>==<version>`) to `[project].dependencies` in `pyproject.toml`.
|
|
30
|
+
|
|
31
|
+
**Remove**
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
hatch project remove <pkg>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Removes `<pkg>` from `[project].dependencies` in `pyproject.toml`.
|
|
38
|
+
|
|
39
|
+
**Update**
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
hatch project remove <pkg>
|
|
43
|
+
hatch project add <pkg>==<version>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
There is no single hatch verb for updating a dependency. Remove the old entry, then add the new one.
|
|
47
|
+
|
|
48
|
+
### dev
|
|
49
|
+
|
|
50
|
+
**Add**
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
hatch project add --dev <pkg>
|
|
54
|
+
# Pinned:
|
|
55
|
+
hatch project add --dev <pkg>==<version>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Appends `<pkg>` (or `<pkg>==<version>`) to `[tool.hatch.envs.default].dependencies` in `pyproject.toml`.
|
|
59
|
+
|
|
60
|
+
**Remove**
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
hatch project remove --dev <pkg>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Removes `<pkg>` from `[tool.hatch.envs.default].dependencies` in `pyproject.toml`.
|
|
67
|
+
|
|
68
|
+
**Update**
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
hatch project remove --dev <pkg>
|
|
72
|
+
hatch project add --dev <pkg>==<version>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Remove the old entry, then add the new one.
|
|
76
|
+
|
|
77
|
+
### build
|
|
78
|
+
|
|
79
|
+
Build-system dependencies (`[build-system].requires`) are not managed by a hatch CLI command.
|
|
80
|
+
Edit `pyproject.toml` directly:
|
|
81
|
+
|
|
82
|
+
**Add** — In the `[build-system]` section, add the entry to the `requires` list:
|
|
83
|
+
|
|
84
|
+
```toml
|
|
85
|
+
[build-system]
|
|
86
|
+
requires = ["hatchling", "<pkg>==<version>"]
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Remove** — Remove the entry from the `requires` list:
|
|
90
|
+
|
|
91
|
+
```toml
|
|
92
|
+
[build-system]
|
|
93
|
+
requires = ["hatchling"]
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**Update** — Change the version string in the `requires` list.
|
|
97
|
+
|
|
98
|
+
After editing, recreate the hatch environment to pick up the change:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
hatch env create
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Conflict Resolution
|
|
105
|
+
|
|
106
|
+
Hatch resolves dependencies lazily when the environment is created. To inspect or force a resolution:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# Recreate the environment (forces fresh resolution)
|
|
110
|
+
hatch env remove default
|
|
111
|
+
hatch env create
|
|
112
|
+
|
|
113
|
+
# List installed packages in the hatch environment
|
|
114
|
+
hatch run pip list
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
There is no lockfile, so transitive dependencies cannot be pinned directly. If a transitive
|
|
118
|
+
dependency version is problematic, add a constraint to the appropriate dependency list
|
|
119
|
+
(`[project].dependencies` for runtime, `[tool.hatch.envs.default].dependencies` for dev)
|
|
120
|
+
and recreate the environment.
|
|
121
|
+
|
|
122
|
+
## Verify
|
|
123
|
+
|
|
124
|
+
After any dependency change, recreate the hatch environment and run the static-analysis + test
|
|
125
|
+
steps to confirm nothing is broken:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
hatch env remove default
|
|
129
|
+
hatch env create
|
|
130
|
+
hatch run lint
|
|
131
|
+
hatch run typecheck
|
|
132
|
+
hatch run test
|
|
133
|
+
```
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Development
|
|
2
|
+
|
|
3
|
+
## Prerequisites
|
|
4
|
+
|
|
5
|
+
| Tool | Version | Notes |
|
|
6
|
+
| -------- | ------------- | ---------------------------------------- |
|
|
7
|
+
| Python | >= 3.12 | Runtime interpreter. |
|
|
8
|
+
| hatch | >= 1.17 | Build manager. Installed at `~/.local/bin/hatch` or on `PATH`. |
|
|
9
|
+
|
|
10
|
+
No additional installation is required — the five scripts below drive hatch directly.
|
|
11
|
+
The hatch environment (defined in `pyproject.toml`) is created automatically on first use.
|
|
12
|
+
|
|
13
|
+
## Build Scripts
|
|
14
|
+
|
|
15
|
+
All scripts are run from the **project root** (`kodo/`). Each script resolves its own path
|
|
16
|
+
relative to its location in `scripts/`, so `cwd` does not matter for the caller.
|
|
17
|
+
|
|
18
|
+
| Script | What it does | Hatch command(s) |
|
|
19
|
+
| --------------------------- | -------------------------------------------------------- | ------------------------------------------ |
|
|
20
|
+
| `scripts/build.{sh,ps1}` | Build wheel + sdist (quick dev build, no version stamp). | `hatch build` |
|
|
21
|
+
| `scripts/format.{sh,ps1}` | Auto-format source with ruff. | `hatch run fmt` |
|
|
22
|
+
| `scripts/static_analysis.{sh,ps1}` | Lint with ruff, then type-check with mypy. | `hatch run lint` && `hatch run typecheck` |
|
|
23
|
+
| `scripts/test.{sh,ps1}` | Run the pytest test suite. | `hatch run test` |
|
|
24
|
+
| `scripts/full_build.{sh,ps1}` | format → build → static_analysis → test, fail fast. | Delegates to the four scripts above. |
|
|
25
|
+
|
|
26
|
+
### Invocation
|
|
27
|
+
|
|
28
|
+
**Linux / macOS:**
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
./scripts/build.sh
|
|
32
|
+
./scripts/format.sh
|
|
33
|
+
./scripts/static_analysis.sh
|
|
34
|
+
./scripts/test.sh
|
|
35
|
+
./scripts/full_build.sh
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Windows (PowerShell):**
|
|
39
|
+
|
|
40
|
+
```powershell
|
|
41
|
+
.\scripts\build.ps1
|
|
42
|
+
.\scripts\format.ps1
|
|
43
|
+
.\scripts\static_analysis.ps1
|
|
44
|
+
.\scripts\test.ps1
|
|
45
|
+
.\scripts\full_build.ps1
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Test Selector
|
|
49
|
+
|
|
50
|
+
`scripts/test` accepts an optional first argument that is passed directly to pytest.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Run the full suite
|
|
54
|
+
./scripts/test.sh
|
|
55
|
+
|
|
56
|
+
# Run a single test file
|
|
57
|
+
./scripts/test.sh test/test_orders.py
|
|
58
|
+
|
|
59
|
+
# Run a single test function
|
|
60
|
+
./scripts/test.sh test/test_orders.py::test_refund
|
|
61
|
+
|
|
62
|
+
# Run by keyword filter
|
|
63
|
+
./scripts/test.sh -k refund
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Because hatch passes `{args}` through to the underlying `pytest` command, any valid
|
|
67
|
+
pytest node-id, path, or flag works as the selector.
|
|
68
|
+
|
|
69
|
+
## Scripts vs. Hatch Direct Commands
|
|
70
|
+
|
|
71
|
+
The five Kodo scripts cover the standard build model. Additional hatch commands are
|
|
72
|
+
available for day-to-day work:
|
|
73
|
+
|
|
74
|
+
| Command | Purpose |
|
|
75
|
+
| ------------------------ | ---------------------------------------------------- |
|
|
76
|
+
| `hatch run check` | Run fmt, lint, typecheck, and tests — no build. |
|
|
77
|
+
| `hatch run build` | Full release pipeline (version stamp, checks, build, post-increment). |
|
|
78
|
+
| `hatch run check-version` | Sync `__version__` in `__init__.py` from `pyproject.toml`. |
|
|
79
|
+
|
|
80
|
+
See [`README.md`](README.md) for the full development cycle and release workflow.
|
|
81
|
+
|
|
82
|
+
## Cross-Platform
|
|
83
|
+
|
|
84
|
+
The project is pure Python with no native extensions. The `.sh` and `.ps1` pairs
|
|
85
|
+
invoke identical hatch commands; there are no host/target differences.
|