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.
Files changed (402) hide show
  1. py_kodo-0.1.5/.gitignore +231 -0
  2. py_kodo-0.1.5/CLAUDE.md +226 -0
  3. py_kodo-0.1.5/DEPENDENCIES.md +133 -0
  4. py_kodo-0.1.5/DEVELOPMENT.md +85 -0
  5. py_kodo-0.1.5/LICENSE +201 -0
  6. py_kodo-0.1.5/PKG-INFO +363 -0
  7. py_kodo-0.1.5/README.md +145 -0
  8. py_kodo-0.1.5/build_number +1 -0
  9. py_kodo-0.1.5/doc/ADDING_A_SUBAGENT.md +110 -0
  10. py_kodo-0.1.5/doc/CHECKPOINTS.md +360 -0
  11. py_kodo-0.1.5/doc/INTERNALS.md +1201 -0
  12. py_kodo-0.1.5/doc/LLM_GATEWAY.md +77 -0
  13. py_kodo-0.1.5/doc/LLM_REGISTRY.md +991 -0
  14. py_kodo-0.1.5/doc/LOCAL_INFERENCE.md +184 -0
  15. py_kodo-0.1.5/doc/LOCAL_MODEL_MANAGER.md +676 -0
  16. py_kodo-0.1.5/doc/READ_WEBPAGE.md +180 -0
  17. py_kodo-0.1.5/doc/SECURITY.md +827 -0
  18. py_kodo-0.1.5/doc/SECURITY_RULES_GUIDE.md +456 -0
  19. py_kodo-0.1.5/doc/SECURITY_RULES_PLAN.md +799 -0
  20. py_kodo-0.1.5/doc/SESSIONS.md +586 -0
  21. py_kodo-0.1.5/doc/SETTINGS.md +132 -0
  22. py_kodo-0.1.5/doc/STATE_AND_LIFECYCLE.md +325 -0
  23. py_kodo-0.1.5/doc/STUCK_DETECTION.md +156 -0
  24. py_kodo-0.1.5/doc/TOOLS.md +688 -0
  25. py_kodo-0.1.5/doc/VALIDATOR.md +480 -0
  26. py_kodo-0.1.5/doc/WEB_SEARCH.md +292 -0
  27. py_kodo-0.1.5/doc/WS_PROTOCOL.md +1729 -0
  28. py_kodo-0.1.5/hatch_build.py +148 -0
  29. py_kodo-0.1.5/pyproject.toml +73 -0
  30. py_kodo-0.1.5/scripts/build.ps1 +10 -0
  31. py_kodo-0.1.5/scripts/build.sh +10 -0
  32. py_kodo-0.1.5/scripts/check_version.py +15 -0
  33. py_kodo-0.1.5/scripts/format.ps1 +10 -0
  34. py_kodo-0.1.5/scripts/format.sh +10 -0
  35. py_kodo-0.1.5/scripts/full_build.ps1 +20 -0
  36. py_kodo-0.1.5/scripts/full_build.sh +21 -0
  37. py_kodo-0.1.5/scripts/post_build.py +23 -0
  38. py_kodo-0.1.5/scripts/pre_build.py +66 -0
  39. py_kodo-0.1.5/scripts/static_analysis.ps1 +14 -0
  40. py_kodo-0.1.5/scripts/static_analysis.sh +13 -0
  41. py_kodo-0.1.5/scripts/test.ps1 +23 -0
  42. py_kodo-0.1.5/scripts/test.sh +23 -0
  43. py_kodo-0.1.5/src/kodo/__init__.py +5 -0
  44. py_kodo-0.1.5/src/kodo/__main__.py +12 -0
  45. py_kodo-0.1.5/src/kodo/binutils/__init__.py +25 -0
  46. py_kodo-0.1.5/src/kodo/binutils/_utils.py +377 -0
  47. py_kodo-0.1.5/src/kodo/common/__init__.py +15 -0
  48. py_kodo-0.1.5/src/kodo/common/_envelope.py +173 -0
  49. py_kodo-0.1.5/src/kodo/common/_protocols.py +72 -0
  50. py_kodo-0.1.5/src/kodo/common/_tempdir.py +44 -0
  51. py_kodo-0.1.5/src/kodo/common/py.typed +0 -0
  52. py_kodo-0.1.5/src/kodo/guided_state/__init__.py +44 -0
  53. py_kodo-0.1.5/src/kodo/guided_state/_paths.py +42 -0
  54. py_kodo-0.1.5/src/kodo/guided_state/_records.py +108 -0
  55. py_kodo-0.1.5/src/kodo/guided_state/_scan.py +40 -0
  56. py_kodo-0.1.5/src/kodo/guided_state/_store.py +143 -0
  57. py_kodo-0.1.5/src/kodo/guided_state/py.typed +0 -0
  58. py_kodo-0.1.5/src/kodo/llms/__init__.py +114 -0
  59. py_kodo-0.1.5/src/kodo/llms/_cloud_registry.py +153 -0
  60. py_kodo-0.1.5/src/kodo/llms/_context.py +54 -0
  61. py_kodo-0.1.5/src/kodo/llms/_gateway.py +295 -0
  62. py_kodo-0.1.5/src/kodo/llms/_hardware.py +150 -0
  63. py_kodo-0.1.5/src/kodo/llms/_interface.py +277 -0
  64. py_kodo-0.1.5/src/kodo/llms/_local_registry.py +2492 -0
  65. py_kodo-0.1.5/src/kodo/llms/_logger.py +185 -0
  66. py_kodo-0.1.5/src/kodo/llms/_sanitize.py +24 -0
  67. py_kodo-0.1.5/src/kodo/llms/_tool_logger.py +73 -0
  68. py_kodo-0.1.5/src/kodo/llms/anthropic/__init__.py +12 -0
  69. py_kodo-0.1.5/src/kodo/llms/anthropic/_cache.py +111 -0
  70. py_kodo-0.1.5/src/kodo/llms/anthropic/_claude.py +260 -0
  71. py_kodo-0.1.5/src/kodo/llms/anthropic/_retry.py +185 -0
  72. py_kodo-0.1.5/src/kodo/llms/anthropic/_usage.py +49 -0
  73. py_kodo-0.1.5/src/kodo/llms/anthropic/py.typed +0 -0
  74. py_kodo-0.1.5/src/kodo/llms/llamacpp/__init__.py +71 -0
  75. py_kodo-0.1.5/src/kodo/llms/llamacpp/_installer.py +519 -0
  76. py_kodo-0.1.5/src/kodo/llms/llamacpp/_llama.py +891 -0
  77. py_kodo-0.1.5/src/kodo/llms/llamacpp/_llama_server.py +474 -0
  78. py_kodo-0.1.5/src/kodo/llms/llamacpp/_manager.py +180 -0
  79. py_kodo-0.1.5/src/kodo/llms/llamacpp/py.typed +0 -0
  80. py_kodo-0.1.5/src/kodo/llms/local/__init__.py +41 -0
  81. py_kodo-0.1.5/src/kodo/llms/local/_hf.py +185 -0
  82. py_kodo-0.1.5/src/kodo/llms/local/_http.py +371 -0
  83. py_kodo-0.1.5/src/kodo/llms/local/_manager.py +772 -0
  84. py_kodo-0.1.5/src/kodo/llms/local/_state.py +129 -0
  85. py_kodo-0.1.5/src/kodo/llms/local/_types.py +166 -0
  86. py_kodo-0.1.5/src/kodo/llms/local/py.typed +0 -0
  87. py_kodo-0.1.5/src/kodo/llms/py.typed +0 -0
  88. py_kodo-0.1.5/src/kodo/mirror/__init__.py +24 -0
  89. py_kodo-0.1.5/src/kodo/mirror/_mirror.py +346 -0
  90. py_kodo-0.1.5/src/kodo/mirror/py.typed +0 -0
  91. py_kodo-0.1.5/src/kodo/project/__init__.py +25 -0
  92. py_kodo-0.1.5/src/kodo/project/_layout.py +363 -0
  93. py_kodo-0.1.5/src/kodo/project/_manifest.py +96 -0
  94. py_kodo-0.1.5/src/kodo/project/py.typed +0 -0
  95. py_kodo-0.1.5/src/kodo/py.typed +0 -0
  96. py_kodo-0.1.5/src/kodo/runtime/__init__.py +32 -0
  97. py_kodo-0.1.5/src/kodo/runtime/_attachments.py +202 -0
  98. py_kodo-0.1.5/src/kodo/runtime/_checkpoints.py +639 -0
  99. py_kodo-0.1.5/src/kodo/runtime/_cyclic_thinking.py +157 -0
  100. py_kodo-0.1.5/src/kodo/runtime/_engine/__init__.py +35 -0
  101. py_kodo-0.1.5/src/kodo/runtime/_engine/_checkpointing.py +308 -0
  102. py_kodo-0.1.5/src/kodo/runtime/_engine/_compaction.py +387 -0
  103. py_kodo-0.1.5/src/kodo/runtime/_engine/_core.py +1218 -0
  104. py_kodo-0.1.5/src/kodo/runtime/_engine/_events.py +377 -0
  105. py_kodo-0.1.5/src/kodo/runtime/_engine/_history.py +661 -0
  106. py_kodo-0.1.5/src/kodo/runtime/_engine/_llm.py +528 -0
  107. py_kodo-0.1.5/src/kodo/runtime/_engine/_proto.py +324 -0
  108. py_kodo-0.1.5/src/kodo/runtime/_engine/_resume.py +389 -0
  109. py_kodo-0.1.5/src/kodo/runtime/_engine/_services.py +127 -0
  110. py_kodo-0.1.5/src/kodo/runtime/_engine/_shared.py +148 -0
  111. py_kodo-0.1.5/src/kodo/runtime/_engine/_subagents.py +576 -0
  112. py_kodo-0.1.5/src/kodo/runtime/_engine/_titling.py +214 -0
  113. py_kodo-0.1.5/src/kodo/runtime/_engine/_turns.py +939 -0
  114. py_kodo-0.1.5/src/kodo/runtime/_engine/_watchdog.py +650 -0
  115. py_kodo-0.1.5/src/kodo/runtime/_engine/_worker.py +167 -0
  116. py_kodo-0.1.5/src/kodo/runtime/_gates.py +639 -0
  117. py_kodo-0.1.5/src/kodo/runtime/_security_rules.py +54 -0
  118. py_kodo-0.1.5/src/kodo/runtime/_session.py +157 -0
  119. py_kodo-0.1.5/src/kodo/runtime/_session_log.py +84 -0
  120. py_kodo-0.1.5/src/kodo/runtime/py.typed +0 -0
  121. py_kodo-0.1.5/src/kodo/security/__init__.py +68 -0
  122. py_kodo-0.1.5/src/kodo/security/_analysis.py +378 -0
  123. py_kodo-0.1.5/src/kodo/security/_classify.py +327 -0
  124. py_kodo-0.1.5/src/kodo/security/_defaults.py +617 -0
  125. py_kodo-0.1.5/src/kodo/security/_layer.py +353 -0
  126. py_kodo-0.1.5/src/kodo/security/_rules.py +835 -0
  127. py_kodo-0.1.5/src/kodo/security/_store.py +171 -0
  128. py_kodo-0.1.5/src/kodo/security/py.typed +0 -0
  129. py_kodo-0.1.5/src/kodo/server/__init__.py +21 -0
  130. py_kodo-0.1.5/src/kodo/server/__main__.py +79 -0
  131. py_kodo-0.1.5/src/kodo/server/_app.py +2041 -0
  132. py_kodo-0.1.5/src/kodo/server/_config.py +164 -0
  133. py_kodo-0.1.5/src/kodo/server/_connection_registry.py +194 -0
  134. py_kodo-0.1.5/src/kodo/server/_key_broker.py +92 -0
  135. py_kodo-0.1.5/src/kodo/server/_lifecycle.py +203 -0
  136. py_kodo-0.1.5/src/kodo/server/_session.py +37 -0
  137. py_kodo-0.1.5/src/kodo/server/_session_manager.py +588 -0
  138. py_kodo-0.1.5/src/kodo/server/py.typed +0 -0
  139. py_kodo-0.1.5/src/kodo/shellparser/__init__.py +23 -0
  140. py_kodo-0.1.5/src/kodo/shellparser/_parser.py +284 -0
  141. py_kodo-0.1.5/src/kodo/shellparser/_powershell.py +204 -0
  142. py_kodo-0.1.5/src/kodo/shellparser/py.typed +0 -0
  143. py_kodo-0.1.5/src/kodo/state/__init__.py +20 -0
  144. py_kodo-0.1.5/src/kodo/state/_toolcall_store.py +130 -0
  145. py_kodo-0.1.5/src/kodo/state/_transient.py +1254 -0
  146. py_kodo-0.1.5/src/kodo/state/py.typed +0 -0
  147. py_kodo-0.1.5/src/kodo/subagents/__init__.py +16 -0
  148. py_kodo-0.1.5/src/kodo/subagents/_loader.py +259 -0
  149. py_kodo-0.1.5/src/kodo/subagents/_registry.py +395 -0
  150. py_kodo-0.1.5/src/kodo/subagents/_subagentspec.py +51 -0
  151. py_kodo-0.1.5/src/kodo/subagents/agent_guide.md +313 -0
  152. py_kodo-0.1.5/src/kodo/subagents/agent_judge.md +85 -0
  153. py_kodo-0.1.5/src/kodo/subagents/agent_problem_solver.md +208 -0
  154. py_kodo-0.1.5/src/kodo/subagents/base_dependencies.md +102 -0
  155. py_kodo-0.1.5/src/kodo/subagents/base_toolchain.md +138 -0
  156. py_kodo-0.1.5/src/kodo/subagents/preamble_performance.md +85 -0
  157. py_kodo-0.1.5/src/kodo/subagents/preamble_security.md +43 -0
  158. py_kodo-0.1.5/src/kodo/subagents/py.typed +0 -0
  159. py_kodo-0.1.5/src/kodo/subagents/specs/__init__.py +105 -0
  160. py_kodo-0.1.5/src/kodo/subagents/specs/_architect.py +33 -0
  161. py_kodo-0.1.5/src/kodo/subagents/specs/_architect_critic.py +27 -0
  162. py_kodo-0.1.5/src/kodo/subagents/specs/_code_critic.py +37 -0
  163. py_kodo-0.1.5/src/kodo/subagents/specs/_coder.py +23 -0
  164. py_kodo-0.1.5/src/kodo/subagents/specs/_compactor.py +33 -0
  165. py_kodo-0.1.5/src/kodo/subagents/specs/_developer.py +92 -0
  166. py_kodo-0.1.5/src/kodo/subagents/specs/_e2e_test_code_critic.py +46 -0
  167. py_kodo-0.1.5/src/kodo/subagents/specs/_e2e_test_coder.py +37 -0
  168. py_kodo-0.1.5/src/kodo/subagents/specs/_e2e_test_design_critic.py +32 -0
  169. py_kodo-0.1.5/src/kodo/subagents/specs/_e2e_test_designer.py +31 -0
  170. py_kodo-0.1.5/src/kodo/subagents/specs/_functional_design_critic.py +31 -0
  171. py_kodo-0.1.5/src/kodo/subagents/specs/_functional_designer.py +29 -0
  172. py_kodo-0.1.5/src/kodo/subagents/specs/_investigator.py +117 -0
  173. py_kodo-0.1.5/src/kodo/subagents/specs/_narrative_author.py +44 -0
  174. py_kodo-0.1.5/src/kodo/subagents/specs/_planner.py +98 -0
  175. py_kodo-0.1.5/src/kodo/subagents/specs/_requirements_author.py +27 -0
  176. py_kodo-0.1.5/src/kodo/subagents/specs/_requirements_critic.py +32 -0
  177. py_kodo-0.1.5/src/kodo/subagents/specs/_shapes.py +188 -0
  178. py_kodo-0.1.5/src/kodo/subagents/specs/_test_coder.py +30 -0
  179. py_kodo-0.1.5/src/kodo/subagents/specs/_test_design_critic.py +33 -0
  180. py_kodo-0.1.5/src/kodo/subagents/specs/_test_designer.py +21 -0
  181. py_kodo-0.1.5/src/kodo/subagents/specs/_toolchain_cpp.py +76 -0
  182. py_kodo-0.1.5/src/kodo/subagents/specs/_toolchain_depsmgr.py +103 -0
  183. py_kodo-0.1.5/src/kodo/subagents/specs/_toolchain_python.py +68 -0
  184. py_kodo-0.1.5/src/kodo/subagents/specs/_toolchain_rust.py +68 -0
  185. py_kodo-0.1.5/src/kodo/subagents/specs/_web_search_agent.py +96 -0
  186. py_kodo-0.1.5/src/kodo/subagents/subagent_architect.md +128 -0
  187. py_kodo-0.1.5/src/kodo/subagents/subagent_architect_critic.md +87 -0
  188. py_kodo-0.1.5/src/kodo/subagents/subagent_code_critic.md +101 -0
  189. py_kodo-0.1.5/src/kodo/subagents/subagent_coder.md +126 -0
  190. py_kodo-0.1.5/src/kodo/subagents/subagent_compactor.md +37 -0
  191. py_kodo-0.1.5/src/kodo/subagents/subagent_developer.md +97 -0
  192. py_kodo-0.1.5/src/kodo/subagents/subagent_e2e_test_code_critic.md +95 -0
  193. py_kodo-0.1.5/src/kodo/subagents/subagent_e2e_test_coder.md +94 -0
  194. py_kodo-0.1.5/src/kodo/subagents/subagent_e2e_test_design_critic.md +82 -0
  195. py_kodo-0.1.5/src/kodo/subagents/subagent_e2e_test_designer.md +123 -0
  196. py_kodo-0.1.5/src/kodo/subagents/subagent_functional_design_critic.md +97 -0
  197. py_kodo-0.1.5/src/kodo/subagents/subagent_functional_designer.md +173 -0
  198. py_kodo-0.1.5/src/kodo/subagents/subagent_investigator.md +73 -0
  199. py_kodo-0.1.5/src/kodo/subagents/subagent_narrative_author.md +181 -0
  200. py_kodo-0.1.5/src/kodo/subagents/subagent_planner.md +59 -0
  201. py_kodo-0.1.5/src/kodo/subagents/subagent_requirements_author.md +107 -0
  202. py_kodo-0.1.5/src/kodo/subagents/subagent_requirements_critic.md +82 -0
  203. py_kodo-0.1.5/src/kodo/subagents/subagent_test_coder.md +83 -0
  204. py_kodo-0.1.5/src/kodo/subagents/subagent_test_design_critic.md +91 -0
  205. py_kodo-0.1.5/src/kodo/subagents/subagent_test_designer.md +96 -0
  206. py_kodo-0.1.5/src/kodo/subagents/subagent_toolchain_cpp.md +84 -0
  207. py_kodo-0.1.5/src/kodo/subagents/subagent_toolchain_depsmgr.md +103 -0
  208. py_kodo-0.1.5/src/kodo/subagents/subagent_toolchain_python.md +73 -0
  209. py_kodo-0.1.5/src/kodo/subagents/subagent_toolchain_rust.md +73 -0
  210. py_kodo-0.1.5/src/kodo/subagents/subagent_web_search.md +94 -0
  211. py_kodo-0.1.5/src/kodo/titling/__init__.py +35 -0
  212. py_kodo-0.1.5/src/kodo/titling/_server.py +574 -0
  213. py_kodo-0.1.5/src/kodo/tools/__init__.py +131 -0
  214. py_kodo-0.1.5/src/kodo/tools/_ask_user.py +77 -0
  215. py_kodo-0.1.5/src/kodo/tools/_context.py +697 -0
  216. py_kodo-0.1.5/src/kodo/tools/_create_directory.py +39 -0
  217. py_kodo-0.1.5/src/kodo/tools/_create_file.py +59 -0
  218. py_kodo-0.1.5/src/kodo/tools/_create_new_project.py +62 -0
  219. py_kodo-0.1.5/src/kodo/tools/_disable_autonomous_mode.py +22 -0
  220. py_kodo-0.1.5/src/kodo/tools/_dispatch.py +572 -0
  221. py_kodo-0.1.5/src/kodo/tools/_document_feedback.py +59 -0
  222. py_kodo-0.1.5/src/kodo/tools/_edit_file.py +114 -0
  223. py_kodo-0.1.5/src/kodo/tools/_edit_review.py +40 -0
  224. py_kodo-0.1.5/src/kodo/tools/_escalate_blocker.py +40 -0
  225. py_kodo-0.1.5/src/kodo/tools/_filesystem.py +145 -0
  226. py_kodo-0.1.5/src/kodo/tools/_finalize_project.py +21 -0
  227. py_kodo-0.1.5/src/kodo/tools/_find_files.py +107 -0
  228. py_kodo-0.1.5/src/kodo/tools/_find_text_in_files.py +136 -0
  229. py_kodo-0.1.5/src/kodo/tools/_get_root_paths.py +43 -0
  230. py_kodo-0.1.5/src/kodo/tools/_get_web_search_state.py +25 -0
  231. py_kodo-0.1.5/src/kodo/tools/_guided_dev_status.py +29 -0
  232. py_kodo-0.1.5/src/kodo/tools/_init_project.py +53 -0
  233. py_kodo-0.1.5/src/kodo/tools/_paths.py +211 -0
  234. py_kodo-0.1.5/src/kodo/tools/_query_search_engine.py +121 -0
  235. py_kodo-0.1.5/src/kodo/tools/_read_attachment.py +47 -0
  236. py_kodo-0.1.5/src/kodo/tools/_read_file.py +164 -0
  237. py_kodo-0.1.5/src/kodo/tools/_read_webpage.py +151 -0
  238. py_kodo-0.1.5/src/kodo/tools/_remaining_time.py +26 -0
  239. py_kodo-0.1.5/src/kodo/tools/_return_result.py +50 -0
  240. py_kodo-0.1.5/src/kodo/tools/_rollback.py +35 -0
  241. py_kodo-0.1.5/src/kodo/tools/_run_author_critic_iteration.py +56 -0
  242. py_kodo-0.1.5/src/kodo/tools/_run_command.py +144 -0
  243. py_kodo-0.1.5/src/kodo/tools/_run_subagent.py +30 -0
  244. py_kodo-0.1.5/src/kodo/tools/_search.py +87 -0
  245. py_kodo-0.1.5/src/kodo/tools/_submit_evaluation.py +56 -0
  246. py_kodo-0.1.5/src/kodo/tools/_tool.py +69 -0
  247. py_kodo-0.1.5/src/kodo/tools/_toolchain_build.py +121 -0
  248. py_kodo-0.1.5/src/kodo/tools/_toolchain_deps.py +135 -0
  249. py_kodo-0.1.5/src/kodo/tools/_update_web_search_state.py +33 -0
  250. py_kodo-0.1.5/src/kodo/tools/_wait.py +33 -0
  251. py_kodo-0.1.5/src/kodo/tools/_web_search.py +75 -0
  252. py_kodo-0.1.5/src/kodo/toolspecs/__init__.py +155 -0
  253. py_kodo-0.1.5/src/kodo/toolspecs/_ask_user.py +127 -0
  254. py_kodo-0.1.5/src/kodo/toolspecs/_compliance.py +212 -0
  255. py_kodo-0.1.5/src/kodo/toolspecs/_create_directory.py +102 -0
  256. py_kodo-0.1.5/src/kodo/toolspecs/_create_file.py +182 -0
  257. py_kodo-0.1.5/src/kodo/toolspecs/_create_new_project.py +99 -0
  258. py_kodo-0.1.5/src/kodo/toolspecs/_disable_autonomous_mode.py +47 -0
  259. py_kodo-0.1.5/src/kodo/toolspecs/_document_feedback.py +96 -0
  260. py_kodo-0.1.5/src/kodo/toolspecs/_edit_file.py +198 -0
  261. py_kodo-0.1.5/src/kodo/toolspecs/_escalate_blocker.py +109 -0
  262. py_kodo-0.1.5/src/kodo/toolspecs/_filesystem.py +201 -0
  263. py_kodo-0.1.5/src/kodo/toolspecs/_finalize_project.py +37 -0
  264. py_kodo-0.1.5/src/kodo/toolspecs/_find_files.py +137 -0
  265. py_kodo-0.1.5/src/kodo/toolspecs/_find_text_in_files.py +160 -0
  266. py_kodo-0.1.5/src/kodo/toolspecs/_get_root_paths.py +113 -0
  267. py_kodo-0.1.5/src/kodo/toolspecs/_get_web_search_state.py +56 -0
  268. py_kodo-0.1.5/src/kodo/toolspecs/_guided_dev_status.py +72 -0
  269. py_kodo-0.1.5/src/kodo/toolspecs/_init_project.py +96 -0
  270. py_kodo-0.1.5/src/kodo/toolspecs/_intent.py +59 -0
  271. py_kodo-0.1.5/src/kodo/toolspecs/_query_search_engine.py +103 -0
  272. py_kodo-0.1.5/src/kodo/toolspecs/_read_attachment.py +60 -0
  273. py_kodo-0.1.5/src/kodo/toolspecs/_read_file.py +154 -0
  274. py_kodo-0.1.5/src/kodo/toolspecs/_read_webpage.py +124 -0
  275. py_kodo-0.1.5/src/kodo/toolspecs/_remaining_time.py +49 -0
  276. py_kodo-0.1.5/src/kodo/toolspecs/_return_result.py +59 -0
  277. py_kodo-0.1.5/src/kodo/toolspecs/_rollback.py +57 -0
  278. py_kodo-0.1.5/src/kodo/toolspecs/_run_author_critic_iteration.py +97 -0
  279. py_kodo-0.1.5/src/kodo/toolspecs/_run_command.py +112 -0
  280. py_kodo-0.1.5/src/kodo/toolspecs/_run_subagent.py +62 -0
  281. py_kodo-0.1.5/src/kodo/toolspecs/_spec.py +117 -0
  282. py_kodo-0.1.5/src/kodo/toolspecs/_submit_evaluation.py +78 -0
  283. py_kodo-0.1.5/src/kodo/toolspecs/_toolchain_build.py +162 -0
  284. py_kodo-0.1.5/src/kodo/toolspecs/_toolchain_deps.py +141 -0
  285. py_kodo-0.1.5/src/kodo/toolspecs/_update_web_search_state.py +69 -0
  286. py_kodo-0.1.5/src/kodo/toolspecs/_visibility.py +77 -0
  287. py_kodo-0.1.5/src/kodo/toolspecs/_wait.py +63 -0
  288. py_kodo-0.1.5/src/kodo/toolspecs/_web_search.py +135 -0
  289. py_kodo-0.1.5/src/kodo/toolspecs/_workspace.py +18 -0
  290. py_kodo-0.1.5/src/kodo/toolspecs/py.typed +0 -0
  291. py_kodo-0.1.5/src/kodo/transport/__init__.py +213 -0
  292. py_kodo-0.1.5/src/kodo/transport/_connection.py +226 -0
  293. py_kodo-0.1.5/src/kodo/transport/_messages.py +894 -0
  294. py_kodo-0.1.5/src/kodo/transport/_outbox.py +102 -0
  295. py_kodo-0.1.5/src/kodo/transport/_ws.py +195 -0
  296. py_kodo-0.1.5/src/kodo/transport/py.typed +0 -0
  297. py_kodo-0.1.5/src/kodo/validator/__init__.py +70 -0
  298. py_kodo-0.1.5/src/kodo/validator/__main__.py +329 -0
  299. py_kodo-0.1.5/src/kodo/validator/_client.py +458 -0
  300. py_kodo-0.1.5/src/kodo/validator/_evaluate.py +378 -0
  301. py_kodo-0.1.5/src/kodo/validator/_harness.py +471 -0
  302. py_kodo-0.1.5/src/kodo/validator/_home.py +136 -0
  303. py_kodo-0.1.5/src/kodo/validator/_models.py +229 -0
  304. py_kodo-0.1.5/src/kodo/validator/_scenario.py +242 -0
  305. py_kodo-0.1.5/src/kodo/validator/_server.py +202 -0
  306. py_kodo-0.1.5/src/kodo/validator/_transcript.py +247 -0
  307. py_kodo-0.1.5/src/kodo/validator/_user.py +204 -0
  308. py_kodo-0.1.5/src/kodo/validator/_vllm.py +353 -0
  309. py_kodo-0.1.5/src/kodo/validator/_workspace.py +170 -0
  310. py_kodo-0.1.5/src/kodo/validator/prompts/__init__.py +18 -0
  311. py_kodo-0.1.5/src/kodo/validator/prompts/_registry.py +108 -0
  312. py_kodo-0.1.5/src/kodo/validator/prompts/tictactoe/detailed_task.md +28 -0
  313. py_kodo-0.1.5/src/kodo/validator/prompts/tictactoe/rvp.md +62 -0
  314. py_kodo-0.1.5/src/kodo/validator/prompts/tictactoe/sparse_task.md +15 -0
  315. py_kodo-0.1.5/src/kodo/validator/prompts/tictactoe/upp.md +37 -0
  316. py_kodo-0.1.5/src/kodo/validator/scenarios/__init__.py +175 -0
  317. py_kodo-0.1.5/src/kodo/validator/scenarios/__main__.py +225 -0
  318. py_kodo-0.1.5/src/kodo/validator/scenarios/qwen35-9b/tictactoe_console.py +40 -0
  319. py_kodo-0.1.5/src/kodo/validator/scenarios/qwen36-27b/tictactoe_upp.py +40 -0
  320. py_kodo-0.1.5/src/kodo/websearch/__init__.py +63 -0
  321. py_kodo-0.1.5/src/kodo/websearch/_browser.py +306 -0
  322. py_kodo-0.1.5/src/kodo/websearch/_curlfetch.py +77 -0
  323. py_kodo-0.1.5/src/kodo/websearch/_enginequery.py +107 -0
  324. py_kodo-0.1.5/src/kodo/websearch/_engines.py +230 -0
  325. py_kodo-0.1.5/src/kodo/websearch/_engines_static.py +240 -0
  326. py_kodo-0.1.5/src/kodo/websearch/_htmlextract.py +307 -0
  327. py_kodo-0.1.5/src/kodo/websearch/_readpage.py +418 -0
  328. py_kodo-0.1.5/src/kodo/websearch/_state.py +129 -0
  329. py_kodo-0.1.5/src/kodo/websearch/_validate.py +71 -0
  330. py_kodo-0.1.5/test/__init__.py +0 -0
  331. py_kodo-0.1.5/test/test_agents.py +635 -0
  332. py_kodo-0.1.5/test/test_attachments.py +145 -0
  333. py_kodo-0.1.5/test/test_browser_session.py +275 -0
  334. py_kodo-0.1.5/test/test_cache.py +286 -0
  335. py_kodo-0.1.5/test/test_checkpoint_state.py +154 -0
  336. py_kodo-0.1.5/test/test_checkpoints.py +145 -0
  337. py_kodo-0.1.5/test/test_claude.py +564 -0
  338. py_kodo-0.1.5/test/test_common_tempdir.py +49 -0
  339. py_kodo-0.1.5/test/test_config.py +82 -0
  340. py_kodo-0.1.5/test/test_connection.py +212 -0
  341. py_kodo-0.1.5/test/test_connection_registry.py +115 -0
  342. py_kodo-0.1.5/test/test_create_new_project.py +49 -0
  343. py_kodo-0.1.5/test/test_cyclic_thinking.py +180 -0
  344. py_kodo-0.1.5/test/test_edit_review.py +407 -0
  345. py_kodo-0.1.5/test/test_engine_checkpointing.py +375 -0
  346. py_kodo-0.1.5/test/test_engine_compaction.py +430 -0
  347. py_kodo-0.1.5/test/test_engine_core.py +1712 -0
  348. py_kodo-0.1.5/test/test_engine_document_flow.py +314 -0
  349. py_kodo-0.1.5/test/test_engine_history.py +802 -0
  350. py_kodo-0.1.5/test/test_engine_llm.py +687 -0
  351. py_kodo-0.1.5/test/test_engine_resume.py +614 -0
  352. py_kodo-0.1.5/test/test_engine_shared_events.py +597 -0
  353. py_kodo-0.1.5/test/test_engine_stop.py +285 -0
  354. py_kodo-0.1.5/test/test_engine_subagents.py +565 -0
  355. py_kodo-0.1.5/test/test_engine_titling.py +324 -0
  356. py_kodo-0.1.5/test/test_engine_turns.py +1107 -0
  357. py_kodo-0.1.5/test/test_engine_watchdog.py +1192 -0
  358. py_kodo-0.1.5/test/test_engine_worker.py +475 -0
  359. py_kodo-0.1.5/test/test_enginequery.py +330 -0
  360. py_kodo-0.1.5/test/test_gates.py +744 -0
  361. py_kodo-0.1.5/test/test_guided_state.py +268 -0
  362. py_kodo-0.1.5/test/test_hardware.py +337 -0
  363. py_kodo-0.1.5/test/test_key_broker.py +141 -0
  364. py_kodo-0.1.5/test/test_lifecycle.py +152 -0
  365. py_kodo-0.1.5/test/test_llama_pure.py +1560 -0
  366. py_kodo-0.1.5/test/test_llama_server.py +119 -0
  367. py_kodo-0.1.5/test/test_llamacpp_installer.py +673 -0
  368. py_kodo-0.1.5/test/test_llm_flavors.py +796 -0
  369. py_kodo-0.1.5/test/test_llm_gateway.py +480 -0
  370. py_kodo-0.1.5/test/test_llm_logger.py +429 -0
  371. py_kodo-0.1.5/test/test_llms_local.py +590 -0
  372. py_kodo-0.1.5/test/test_manifest.py +114 -0
  373. py_kodo-0.1.5/test/test_readpage.py +313 -0
  374. py_kodo-0.1.5/test/test_resume_ledger.py +167 -0
  375. py_kodo-0.1.5/test/test_retry.py +380 -0
  376. py_kodo-0.1.5/test/test_sanitize.py +59 -0
  377. py_kodo-0.1.5/test/test_security_layer.py +622 -0
  378. py_kodo-0.1.5/test/test_security_path_store.py +82 -0
  379. py_kodo-0.1.5/test/test_security_rules.py +832 -0
  380. py_kodo-0.1.5/test/test_security_rules_module.py +188 -0
  381. py_kodo-0.1.5/test/test_security_store.py +62 -0
  382. py_kodo-0.1.5/test/test_server_integration.py +1099 -0
  383. py_kodo-0.1.5/test/test_session_log.py +136 -0
  384. py_kodo-0.1.5/test/test_session_manager.py +314 -0
  385. py_kodo-0.1.5/test/test_session_state.py +49 -0
  386. py_kodo-0.1.5/test/test_shadow_mirror.py +211 -0
  387. py_kodo-0.1.5/test/test_shellparser.py +195 -0
  388. py_kodo-0.1.5/test/test_subagentspecs.py +168 -0
  389. py_kodo-0.1.5/test/test_thinking_budget.py +192 -0
  390. py_kodo-0.1.5/test/test_thinking_stream_parser.py +43 -0
  391. py_kodo-0.1.5/test/test_titling.py +498 -0
  392. py_kodo-0.1.5/test/test_tools_compliance.py +1068 -0
  393. py_kodo-0.1.5/test/test_tools_guide.py +347 -0
  394. py_kodo-0.1.5/test/test_tools_leaf.py +1244 -0
  395. py_kodo-0.1.5/test/test_tools_paths.py +69 -0
  396. py_kodo-0.1.5/test/test_transient.py +726 -0
  397. py_kodo-0.1.5/test/test_transport.py +342 -0
  398. py_kodo-0.1.5/test/test_usage.py +108 -0
  399. py_kodo-0.1.5/test/test_validator.py +1030 -0
  400. py_kodo-0.1.5/test/test_validator_harness.py +333 -0
  401. py_kodo-0.1.5/test/test_validator_server.py +258 -0
  402. py_kodo-0.1.5/test/test_websearch.py +328 -0
@@ -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
@@ -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.