tether-sdk 0.2.7__tar.gz → 0.2.9__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 (223) hide show
  1. {tether_sdk-0.2.7/.claude/feature-context → tether_sdk-0.2.9/.claude/gru}/active/v0-2-bugs.md +46 -11
  2. tether_sdk-0.2.9/.claude/gru/archive/work-on-v0-2-4.md +85 -0
  3. tether_sdk-0.2.9/.claude/gru.json +12 -0
  4. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/AGENTS.md +11 -5
  5. tether_sdk-0.2.7/docs/testing.md → tether_sdk-0.2.9/CONTRIBUTING.md +34 -3
  6. tether_sdk-0.2.9/PKG-INFO +143 -0
  7. tether_sdk-0.2.9/README.md +122 -0
  8. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/README.md +1 -1
  9. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/docs/architecture.md +2 -0
  10. tether_sdk-0.2.9/docs/benchmarks.md +50 -0
  11. tether_sdk-0.2.9/docs/extending.md +54 -0
  12. tether_sdk-0.2.9/docs/glossary.md +29 -0
  13. tether_sdk-0.2.9/docs/guides/a-pipeline-with-checks.md +70 -0
  14. tether_sdk-0.2.9/docs/guides/add-your-own-tool.md +62 -0
  15. tether_sdk-0.2.9/docs/guides/fix-a-failing-test.md +65 -0
  16. tether_sdk-0.2.9/docs/guides/use-tether-from-your-agent.md +66 -0
  17. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/docs/index.md +18 -0
  18. tether_sdk-0.2.9/docs/llms.txt +45 -0
  19. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/docs/reference/agent-interface.md +2 -0
  20. tether_sdk-0.2.9/docs/reference/cli.md +287 -0
  21. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/docs/reference/index.md +2 -0
  22. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/docs/reference/providers.md +115 -78
  23. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/docs/release-notes.md +37 -1
  24. tether_sdk-0.2.9/docs/troubleshooting.md +117 -0
  25. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/docs/tutorial/agent-interface.md +3 -19
  26. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/docs/tutorial/built-in-tools.md +2 -0
  27. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/docs/tutorial/cli-and-headless.md +2 -0
  28. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/docs/tutorial/index.md +3 -1
  29. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/docs/tutorial/multi-agent.md +2 -0
  30. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/docs/tutorial/sdk-and-custom-tools.md +2 -0
  31. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/docs/tutorial/security-and-sandbox.md +2 -0
  32. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/docs/tutorial/skills.md +2 -0
  33. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/docs/tutorial/workflows-and-telemetry.md +2 -0
  34. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/e2e/test_quirks.py +12 -0
  35. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/mkdocs.yml +12 -8
  36. tether_sdk-0.2.9/tests/test_benchmarks_docs.py +21 -0
  37. tether_sdk-0.2.9/tests/test_cli_docs.py +46 -0
  38. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/test_context.py +6 -0
  39. tether_sdk-0.2.9/tests/test_docs_structure.py +46 -0
  40. tether_sdk-0.2.9/tests/test_guides_docs.py +20 -0
  41. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/test_harness.py +26 -0
  42. tether_sdk-0.2.9/tests/test_llms_txt.py +31 -0
  43. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/test_params.py +55 -0
  44. tether_sdk-0.2.9/tests/test_providers_docs.py +36 -0
  45. tether_sdk-0.2.9/tests/test_readme.py +26 -0
  46. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/test_sandbox.py +53 -0
  47. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/test_tether.py +1 -1
  48. tether_sdk-0.2.9/tests/test_troubleshooting_docs.py +25 -0
  49. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/__init__.py +1 -1
  50. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/context.py +2 -1
  51. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/harness.py +12 -2
  52. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/providers/base.py +6 -1
  53. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/providers/ollama.py +14 -0
  54. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/sandbox.py +24 -2
  55. tether_sdk-0.2.7/PKG-INFO +0 -429
  56. tether_sdk-0.2.7/README.md +0 -408
  57. tether_sdk-0.2.7/docs/benchmarks.md +0 -31
  58. tether_sdk-0.2.7/docs/extending.md +0 -107
  59. tether_sdk-0.2.7/docs/releasing.md +0 -9
  60. tether_sdk-0.2.7/docs/troubleshooting.md +0 -39
  61. {tether_sdk-0.2.7/.claude/feature-context → tether_sdk-0.2.9/.claude/gru}/active/.gitkeep +0 -0
  62. {tether_sdk-0.2.7/.claude/feature-context → tether_sdk-0.2.9/.claude/gru}/archive/.gitkeep +0 -0
  63. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/.github/workflows/ci.yml +0 -0
  64. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/.github/workflows/delivery.yml +0 -0
  65. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/.github/workflows/docs.yml +0 -0
  66. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/.gitignore +0 -0
  67. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/LICENSE +0 -0
  68. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/grade.py +0 -0
  69. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/harness-bench/README.md +0 -0
  70. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/harness-bench/tether-adapter.patch +0 -0
  71. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/naive_agent.py +0 -0
  72. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/report.py +0 -0
  73. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/run.py +0 -0
  74. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-hard/goal.txt +0 -0
  75. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-hard/hidden/test_hidden.py +0 -0
  76. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-hard/ref/calc/__init__.py +0 -0
  77. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-hard/ref/calc/errors.py +0 -0
  78. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-hard/ref/calc/evaluator.py +0 -0
  79. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-hard/ref/calc/parser.py +0 -0
  80. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-hard/ref/calc/tokenizer.py +0 -0
  81. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-hard/ws/calc/__init__.py +0 -0
  82. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-hard/ws/calc/errors.py +0 -0
  83. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-hard/ws/calc/evaluator.py +0 -0
  84. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-hard/ws/calc/parser.py +0 -0
  85. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-hard/ws/calc/tokenizer.py +0 -0
  86. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-hard/ws/tests/__init__.py +0 -0
  87. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-hard/ws/tests/test_calc.py +0 -0
  88. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-medium/goal.txt +0 -0
  89. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-medium/hidden/test_hidden.py +0 -0
  90. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-medium/ws/cli.py +0 -0
  91. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-medium/ws/ledger/__init__.py +0 -0
  92. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-medium/ws/ledger/parser.py +0 -0
  93. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-medium/ws/ledger/report.py +0 -0
  94. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-medium/ws/sample.csv +0 -0
  95. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-medium/ws/tests/__init__.py +0 -0
  96. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-medium/ws/tests/test_report.py +0 -0
  97. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-simple/goal.txt +0 -0
  98. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-simple/hidden/test_hidden.py +0 -0
  99. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-simple/ws/tests/__init__.py +0 -0
  100. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-simple/ws/tests/test_textutils.py +0 -0
  101. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/code-simple/ws/textutils.py +0 -0
  102. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/codereview/goal.txt +0 -0
  103. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/codereview/ws/inventory.py +0 -0
  104. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/content/goal.txt +0 -0
  105. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/content/ws/.keep +0 -0
  106. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/focus/goal.txt +0 -0
  107. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/focus/hidden/test_hidden.py +0 -0
  108. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/focus/ws/AGENTS.md +0 -0
  109. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/focus/ws/README.md +0 -0
  110. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/focus/ws/docs/architecture.md +0 -0
  111. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/focus/ws/docs/style.md +0 -0
  112. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/focus/ws/mini/__init__.py +0 -0
  113. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/focus/ws/mini/cli.py +0 -0
  114. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/focus/ws/mini/fmt.py +0 -0
  115. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/focus/ws/mini/stats.py +0 -0
  116. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/focus/ws/mini/textio.py +0 -0
  117. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/focus/ws/tests/__init__.py +0 -0
  118. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/focus/ws/tests/test_stats.py +0 -0
  119. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/plan/goal.txt +0 -0
  120. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/plan/ws/README.md +0 -0
  121. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/plan/ws/svc/__init__.py +0 -0
  122. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/plan/ws/svc/client.py +0 -0
  123. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/plan/ws/svc/config.py +0 -0
  124. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/qa/goal.txt +0 -0
  125. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/qa/ws/.keep +0 -0
  126. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/review/goal.txt +0 -0
  127. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/bench/tasks/review/ws/paper.md +0 -0
  128. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/docs/javascripts/mathjax.js +0 -0
  129. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/docs/reference/context-and-store.md +0 -0
  130. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/docs/reference/harness.md +0 -0
  131. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/docs/reference/multiplexer-and-decorator.md +0 -0
  132. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/docs/reference/sandbox-and-skills.md +0 -0
  133. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/docs/reference/tools.md +0 -0
  134. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/e2e/__init__.py +0 -0
  135. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/e2e/conftest.py +0 -0
  136. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/e2e/proxy.py +0 -0
  137. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/e2e/test_agents.py +0 -0
  138. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/e2e/test_defaults.py +0 -0
  139. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/e2e/test_faults.py +0 -0
  140. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/e2e/test_lifecycle.py +0 -0
  141. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/e2e/test_limits.py +0 -0
  142. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/e2e/test_sandbox.py +0 -0
  143. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/e2e/test_surface.py +0 -0
  144. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/examples/course/README.md +0 -0
  145. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/examples/course/checks.py +0 -0
  146. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/examples/course/course.yaml +0 -0
  147. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/examples/course/ruff.toml +0 -0
  148. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/examples/course/skills/planner/SKILL.md +0 -0
  149. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/examples/course/skills/searcher/SKILL.md +0 -0
  150. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/examples/course/skills/searcher/tools.py +0 -0
  151. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/examples/course/skills/writer/SKILL.md +0 -0
  152. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/examples/course/skills/writer/tools.py +0 -0
  153. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/pyproject.toml +0 -0
  154. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/scripts/record_golden.py +0 -0
  155. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/skills/researcher/SKILL.md +0 -0
  156. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/__init__.py +0 -0
  157. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/conftest.py +0 -0
  158. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/fixtures/dialects.jsonl +0 -0
  159. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/golden/coding_edit_failure_modes.json +0 -0
  160. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/golden/coding_edit_failure_modes.snap.json +0 -0
  161. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/golden/done_nudge.json +0 -0
  162. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/golden/done_nudge.snap.json +0 -0
  163. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/golden/read_range_pingpong.json +0 -0
  164. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/golden/read_range_pingpong.snap.json +0 -0
  165. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/golden/research_web.json +0 -0
  166. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/golden/research_web.snap.json +0 -0
  167. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/golden/shell_wrappers.json +0 -0
  168. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/golden/shell_wrappers.snap.json +0 -0
  169. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/golden/waiting_input_resume.json +0 -0
  170. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/golden/waiting_input_resume.snap.json +0 -0
  171. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/providers/__init__.py +0 -0
  172. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/providers/test_anthropic.py +0 -0
  173. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/providers/test_base.py +0 -0
  174. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/providers/test_declarative.py +0 -0
  175. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/providers/test_dialects.py +0 -0
  176. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/providers/test_ollama.py +0 -0
  177. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/providers/test_openai.py +0 -0
  178. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/providers/test_retry.py +0 -0
  179. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/test_agent_interface.py +0 -0
  180. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/test_cli.py +0 -0
  181. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/test_context_config.py +0 -0
  182. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/test_decorator.py +0 -0
  183. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/test_edit_tool.py +0 -0
  184. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/test_golden.py +0 -0
  185. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/test_integration.py +0 -0
  186. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/test_misses.py +0 -0
  187. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/test_multiplexer.py +0 -0
  188. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/test_pipeline.py +0 -0
  189. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/test_release_hardening.py +0 -0
  190. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/test_retro.py +0 -0
  191. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/test_security_hardening.py +0 -0
  192. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/test_skills.py +0 -0
  193. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/test_store.py +0 -0
  194. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/test_structured_history.py +0 -0
  195. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/tools/__init__.py +0 -0
  196. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/tools/test_agent.py +0 -0
  197. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/tools/test_bash.py +0 -0
  198. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/tools/test_done.py +0 -0
  199. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/tools/test_edit.py +0 -0
  200. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/tools/test_mem.py +0 -0
  201. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tests/tools/test_web.py +0 -0
  202. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/api.py +0 -0
  203. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/cli.py +0 -0
  204. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/decorator.py +0 -0
  205. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/mcp.py +0 -0
  206. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/multiplexer.py +0 -0
  207. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/pipeline.py +0 -0
  208. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/providers/__init__.py +0 -0
  209. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/providers/anthropic.py +0 -0
  210. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/providers/declarative.py +0 -0
  211. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/providers/openai.py +0 -0
  212. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/retro.py +0 -0
  213. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/schema.py +0 -0
  214. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/skills.py +0 -0
  215. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/store.py +0 -0
  216. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/tools/__init__.py +0 -0
  217. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/tools/agent.py +0 -0
  218. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/tools/bash.py +0 -0
  219. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/tools/done.py +0 -0
  220. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/tools/edit.py +0 -0
  221. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/tools/mem.py +0 -0
  222. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/tether/tools/web.py +0 -0
  223. {tether_sdk-0.2.7 → tether_sdk-0.2.9}/uv.lock +0 -0
@@ -1,7 +1,7 @@
1
1
  # v0.2 bugs
2
2
  - Slug: v0-2-bugs
3
3
  - Status: active
4
- - Started: 2026-10-20 Updated: 2026-10-20 Closed: —
4
+ - Started: 2026-10-20 Updated: 2026-10-24 Closed: —
5
5
  - Branches / PRs: branch `claude/keep-feature-context-resume-0ec918` (worktree); base `main` at 125b386 (release v0.2.2)
6
6
 
7
7
  ## Goal
@@ -10,6 +10,9 @@ Track and fix bugs found in Tether v0.2.x. Exact bug list not yet given by PO.
10
10
  ## Requests
11
11
  - 2026-10-20: Close v0.2.2 milestone; implement v0.2.3 issues (#40 #39 #33 #24) via swe+tether(GLM), watch tether behavior and report bugs; open v0.2.4 issue for provider docs (YAML + Python, generic example, where providers.yaml lives); review docs overall and report.
12
12
  - 2026-10-20: `/keep-feature-context new v0.2 bugs` (start log for v0.2 bugs work)
13
+ - 2026-10-21..24 (backfilled, close to verbatim): choose 4 issues for v0.2.5 and move the rest; fix #92 (+#89 `tether stop`), #81, #76, #86; register NVIDIA models (Nemotron 3 Ultra, Kimi K2.6, GLM-5.2, Mistral Large 3); post-release check v0.2.4 vs v0.2.5 with 3 models; viability of Harness-Bench (harness-bench.ai); sandbox explanation and an issue for 10/10; start using tether as SWE agent; release v0.2.5 and v0.2.6; file new issues and keep 4-5 issues per milestone.
14
+ - 2026-10-24 (backfilled): install v0.2.6 and find a smaller benchmark. Then: "Our main impossible goal is to get the highest score on Polyglot! Leave aside new features unless they help the score." Implement what is needed, release v0.2.7, run the benchmark, plan v0.2.8 from the results.
15
+ - 2026-10-24: PO: v0.2.7 improved or not (answer in plain words); "reading the whole file at once will fill the context faster?"; "are you logging with the keep-feature skill?" (answer: no, resumed and backfilled now).
13
16
 
14
17
  ## Decisions
15
18
  - 2026-10-20: PO convention: v0.X.0 = feature releases (many issues OK), v0.X.Y = bug releases (small, 3-4). All 13 features now in single milestone v0.3 (v0.3.1-v0.3.3 deleted). Bug releases v0.2.4-v0.2.8 unchanged.
@@ -20,6 +23,12 @@ Track and fix bugs found in Tether v0.2.x. Exact bug list not yet given by PO.
20
23
  - 2026-10-20: PO made me act as Team Leader (no product code; dispatch swe/qa/reviewer). swe delegates coding to tether; PO wants it run with GLM and observed for tether bugs.
21
24
  - 2026-10-20: #24 -> opt-in kept + load-time warning + docs fix (maintainer lean, PO approved).
22
25
  - 2026-10-20: Added `## Dev team specifics` to AGENTS.md (PR per task, hard stop = force push/history rewrite, store in-repo `.claude/feature-context/`).
26
+ - 2026-10-24 (backfilled): PO: 4-5 issues per milestone, create v0.2.X as needed; run `TETHER_E2E=1 uv run pytest e2e` before merging and put it in the PR; merges and releases only on explicit PO yes (classifier blocked one merge until PO said go).
27
+ - 2026-10-24: ONE focus = Polyglot-Python score (Aider polyglot, 34 Python exercises, graded by the exercise tests, test file restored before grading). Fast set = 12 exercises, 2 trials. Models: ollama/qwen3.5:9b (main), nemotron-3.5-lightning-30b-a3b on NVIDIA (second), Ultra only as an occasional ceiling check. `think=false` not adopted (79s vs 72s per run on 3 exercises, no clear gain).
28
+ - 2026-10-24: v0.2.7 ships only #138 and #141 (what the failure breakdown justified). Nudge issues (#132-#136) parked until the score says they matter. v0.2.8 starts with #144 (generation headroom).
29
+ - 2026-10-24: milestones now v0.2.8 {#144,#27,#132,#136,#137}, v0.2.9 {#145,#79,#133,#134,#135}, v0.2.10 {#60-#64}, v0.2.11 {#65,#66}; v0.3 holds the 14 feature issues (sandbox #124, Harness-Bench #123, edit tool #78/#34).
30
+
31
+ - 2026-10-24: PO: keep using tether as the swe agent with the strongest FREE model = `nvidia/nvidia/nemotron-3-ultra-550b-a55b` (docs/reference/providers.md: only free model that works; Kimi 404, GLM-5.2 EOL, GLM-5.3 as fallback; rpm 36). #144 bench running (base v0.2.7 venv vs head, polyglot-fast qwen3.5:9b x2) then e2e, then PR.
23
32
 
24
33
  ## Problems
25
34
  - 2026-10-20: reviewer agent's own `gh pr review --comment` got blocked ('Unrequested Commit in a Connected App') and its merge condition needs a 'QA: GOOD TO GO' comment; TL posted the review+merge itself on PO instruction, works. Project has no QA layer beyond CI.
@@ -27,6 +36,11 @@ Track and fix bugs found in Tether v0.2.x. Exact bug list not yet given by PO.
27
36
  - 2026-10-20 TETHER+GLM BUGS (from swe #24): (a) ses_bde86e86 glm-5.3 with --tools bash,edit: 38 steps/90k prompt tokens, read-loop alternating `sed -n 1,40p` / `40,100p` of same file, never edited; every assistant turn empty text + command only; no nudge/loop_stall recorded (= issue #39, cycle detection needed); ended `ReadTimeout` raised as tool_error/Worker error after ~5 min (httpx timeout not retried/handled). (b) ses_6176f368: without --tools bash,edit GLM had only `done`, spent 38 steps probing "unknown command", then WAITING_INPUT asking for a shell (tether default zero tools; unknown-command loops not nudged; could hint 'enabled tools: done' / tools to enable). (c) 401 shows raw HTTPStatusError, doesn't name NVIDIA_API_KEY. (d) swe worktree guard blocks eval/export/time in bash -> key loading needs a script file.
28
37
  - 2026-10-20: swe #40 blocked: tether session ses_29d41cff (nvidia/z-ai/glm-5.3) -> 401 Unauthorized, 0 steps. NVIDIA_API_KEY missing/invalid in tether MCP server env. #24 swe confirmed same (ses_4a589057, 401, 686 ms). Both local branches empty, no PRs. Tether finding: 401 surfaces as raw HTTPStatusError, should name NVIDIA_API_KEY. Needs PO to supply key to MCP server env (not via me).
29
38
  (none yet)
39
+ - 2026-10-24 (backfilled) FOUND BY POLYGLOT BASELINE (tether 0.2.6, qwen3.5:9b, 34 exercises: 14 pass, 41%; naive loop 8, 24%): 13 of 34 runs died as worker_error: 11 Ollama HTTP 500 `invalid tool call arguments for "act": unexpected end of JSON input`, 2 chat-template 500s (`CallExpression`, unknown cause, #145). post_with_retry retried the same request 3x. FIXED in #138/PR #139 (provider-agnostic `rejected_call`, hint to the model).
40
+ - 2026-10-24: ROOT CAUSE of step-cap runs (fast set, 24/48 hit 30 steps): fixed 2,400-char observation cap cut 6-12 KB test files to head+tail, so models re-read the same file 10+ times (45% of capped-run steps were reads, 19% edits). FIXED in #141/PR #142 (cap = max(2400, max_context_tokens*4/3)). Measured: qwen mean 0.64->0.80, re-reads 32%->19% of steps; Lightning pass 10->12/24 (8 of its 24 runs invalid, NVIDIA timeouts). Cost: prompt/step 5.3k->6.4k tokens, run total 106k->126k.
41
+ - 2026-10-24 OPEN (#144): cut-off tool-call hint still fires 42-45 times per 24 qwen runs (about half the runs); prompt before a cut-off median 7,553 tokens vs 5,453 normal, num_ctx 8,192: prompt fills the window, no room for the reply. The cap change did not reduce it.
42
+ - 2026-10-24: bench pitfalls fixed/known: naive_agent needs httpx (run bench with `uv run --with httpx`); `pgrep -f` in a wait loop matches its own shell (use PID); `bench/run.py is_infra` treats ProviderError as infra and hides real failures (report.py now splits); uv index lags PyPI (`uv tool install --refresh`); after `pkill` on bench, a cell dir can be deleted mid-run.
43
+ - 2026-10-24: verify gate at `done` gave only +0.08 mean on the 20 failing exercises (1 more pass): gate alone is not the lever. check-on-change prototype parked at /tmp/claude-1000/poly/check-on-change.snippet (not in repo).
30
44
 
31
45
  ## Progress log
32
46
  - 2026-10-20: RELEASED v0.2.3: release PR #94 merged (ec32d63), GitHub Release v0.2.3 'Small-Model Robustness', delivery.yml success, PyPI tether-sdk 0.2.3 live, milestone v0.2.3 closed. Next: v0.2.4 (#27 #60 #74-#79 #81-#82 #85-#86 #88-#90 #92-#93) and v0.2.5 docs (#61-#66).
@@ -56,20 +70,41 @@ Track and fix bugs found in Tether v0.2.x. Exact bug list not yet given by PO.
56
70
  - 2026-10-20: milestone v0.2.2 closed. Issue #60 created (v0.2.4, provider docs). Docs review agent launched (read-only).
57
71
  - 2026-10-20 (backfilled): preflight ran; AGENTS.md section + `.claude/feature-context/{active,archive}` created (uncommitted).
58
72
  - Checks: `uv run ruff check . && uv run ruff format --check .`; `uv run mypy tether/`; `uv run pytest`.
73
+ - 2026-10-24 (backfilled) RELEASES: v0.2.5 (#76 #81 #86 #89 #92 + NVIDIA models docs), v0.2.6 (#77 #93 #125 #127; PR #131), v0.2.7 (#138 #141 + Polyglot bench; PRs #139 #140 #142, release PR #143, merge 97cbf3e, GitHub Release v0.2.7, PyPI tether-sdk 0.2.7 live, milestone closed). All with e2e 65/65 and 100% coverage before merge.
74
+ - 2026-10-24: post-release check v0.2.4 vs v0.2.5 (3 models, 8 tasks): Ultra 0.943->0.946, Lightning 0.721->0.902, qwen3.5:9b 0.668->0.813. Issues filed: #123 Harness-Bench real run, #124 sandbox 10/10, #132-#137 findings.
75
+ - 2026-10-24: v0.2.6 vs v0.2.7 on the same 12 exercises, qwen: 3/12 pass mean 0.66 -> 9/24 pass mean 0.80 (1 vs 2 runs per exercise, modest evidence).
76
+ - 2026-10-24: PRs: #139 (#138 rejected tool call, +follow-up commit making it agnostic across ollama/openai/anthropic after PO asked), #140 bench, #142 cap, #143 release. Issues: #138, #141 (closed), #144 headroom (v0.2.8), #145 template 500 (v0.2.9).
77
+ - 2026-10-24: re-run of Lightning infra-failed cells on installed 0.2.7 running (out dir /tmp/claude-1000/poly/cap-027, log log-redo-027.txt); results not read yet.
59
78
 
60
79
  ## Next steps
61
- - [x] Release v0.2.3 done
62
- - [ ] Start v0.2.4: #85 #88 #75 #74
63
- - [ ] PO OK to merge #73 (post review comment first, then squash merge); then swe #33 (harness.py), then #69-#72, #74-#79 as scheduled
64
- - [ ] Get GLM model id from PO (not in ~/.tether/providers.yaml; only claude-cli + nvidia entries; no 'glm' anywhere on disk). PO says it was added, maybe in another worktree/host: not found.
65
- - [ ] Dispatch swe for #40 #39 #33 #24 (own PRs; #39/#33 both touch harness -> sequence), then qa+reviewer
66
- - [ ] swe for #60 docs
67
- - [ ] Relay docs review report to PO
68
- - [ ] PO to list the v0.2 bugs
69
- - [ ] Commit AGENTS.md + feature-context log on this branch
80
+ - [x] Release v0.2.3, v0.2.4(not logged), v0.2.5, v0.2.6, v0.2.7
81
+ - [ ] Read the re-run of Lightning cells (cap-027) and update the v0.2.7 numbers
82
+ - [ ] v0.2.8: #144 headroom first (test on fast set vs cap-027: hint rate, no-action steps, prompt size, score), then #27, #132, #136, #137
83
+ - [ ] v0.2.9: #145 template 500 (reproduce), #79, #133, #134, #135
84
+ - [ ] Narrow `is_infra` in bench/run.py (known, noted in #138)
85
+ - [ ] Harness-Bench #123 blocked: docker bridge->host firewall (sudo) + NVIDIA key file from PO
86
+ - [ ] MCP server still on an old process: PO to reconnect (0.2.7 installed locally)
70
87
 
71
88
  ## Sessions
89
+ | 2026-10-25 | /gru takes over: store moved to .claude/gru/, AGENTS.md + .claude/gru.json updated (PR chore/gru-takeover) |
72
90
  | Date | Session note |
73
- | 2026-10-20 | Current session: created log |
91
+ | 2026-10-20 | created log |
92
+ | 2026-10-24 | resumed, backfilled v0.2.4-v0.2.7 (log had stopped at v0.2.3) |
93
+ | 2026-10-24 | resumed in worktree token-usage-analysis-de8182; copied this newer log from worktree tether-v0-2-mcp-89325e (release/v0.2.7), the live one |
74
94
 
75
95
  - 2026-10-20: PO asked: add Philosophy Gate to AGENTS.md (done, uncommitted; also fixed coverage line: CI enforces 100%). Switch swe tether model to `nvidia/nvidia/nemotron-3-ultra-550b-a55b` (exists on NVIDIA API, smoke test `done pong` passed via tether 0.2.3; no providers.yaml change needed, `nvidia` prefix covers it). Upgraded installed tether 0.2.2 -> 0.2.3 (`uv tool upgrade tether-sdk`). MCP server still on old process: needs reconnect to load 0.2.3 + key wrapper.
96
+
97
+ ## Gru run 2026-10-25
98
+ - PRs: #146 (#144 headroom, 1/8; testing 1/4 on bench), #148 (gru takeover), #136 branch fix/136-escalate-loop-stall (worktree .claude/worktrees/gru-136, commit pending PR until codereview bench).
99
+ - Ledger: #136 | Tier 0 | nvidia/nemotron-3-ultra-550b-a55b | tether | ses_2a9da3da | attempt 1 | peak 8.5k ctx, 40 steps | result: code correct (consecutive counter), but FAILED max_steps; I fixed line length (E501), added e2e + release note. Acceptance test (pre-written) passes.
100
+ - Tether friction (ses_2a9da3da): steps 30-40 wasted because `.venv/bin/pytest` is not runnable inside the bash sandbox (venv python symlinks live under hidden /home; `which pytest` empty, `pip install` impossible). Related #76 (PATH under $HOME) but for venvs in the workspace. Also ~13 of 40 steps were `sed -n a,bp` re-reads of harness.py before the first edit (#78/#27 family), and the card's --verify gate used the same unrunnable path. Not yet filed.
101
+ - 2026-10-25 #144: 1/4 headroom bench: hints 29->2, nudges 98->11 (19%->2.2%), pass 11/24 vs 10, mean 0.756 vs 0.741; e2e 65 pass; PR #146 updated, awaits PO merge yes.
102
+ - 2026-10-25 #136: tether(Ultra) wrote correct code but hit max_steps (pytest unrunnable in sandbox). Bench codereview qwen3.5:9b 0/2 Stalled with the new wording AND with output-in-warning variant: model repeats the same empty-content call regardless of message. Not merged, no PR; findings on #136; next hypothesis: break determinism after a loop_stall (temperature bump) or think param.
103
+ - Next (gru pick): friction issue 'pytest/venv unrunnable in bash sandbox' (blocks tether-as-swe, evidence: ses_2a9da3da steps 30-40) -> clear improvement for dogfooding; then #145 reproduce, #27.
104
+ - 2026-10-25 MERGED (PO yes): #146 (#144, 1/4 headroom), #148 (gru takeover). PR #149 (sandbox venv under HOME, follow-up to #76): before exit 127 / after exit 0 for .venv/bin/pytest in bwrap; unit+bwrap tests; e2e 65 pass; awaits PO merge yes.
105
+ - Next picks (gru): validate #149 by re-running a small tether-as-swe card with a --verify gate on .venv/bin/pytest; then #145 (ollama chat-template 500, reproduce), #27 (folding placeholders), #136 retry with temperature bump after loop_stall. Main checkout is stale (local main diverged from origin/main by two pre-squash log commits): PO to OK `git reset --hard origin/main` there.
106
+ - 2026-10-25 PO: docs plan. Audit -> epic #150 (steps: CLI ref #61, providers #60+#62, site structure #151, story guides #152, troubleshooting #153, benchmarks #154, README #63, llms.txt #64, polish #65/#66), all in milestone v0.2.10 (v0.2.11 closed, empty). AGENTS.md 5.6 now states the two audiences (docs site = users/integrators, no bug history; README = evaluate/build/contribute). #145 fix on branch fix/79-stats-offenders awaiting fast-set bench then PR.
107
+ - 2026-10-25 Tether friction (docs cards on Nemotron Ultra): (1) ses_f6f847e5 CLI page and ses_7fb5863b providers page both ended at max steps WITHOUT calling done after the work was finished (keeps verifying); (2) rewriting a docs page it invented API facts (wrong ModelResponse fields, register_provider signature, nonexistent settings) -> docs rewrites by tether need a gru fact-check or assemble-from-source approach; (3) 5 steps in 10 min on a 156-line page (slow generation of long outputs on the free endpoint). Merged: #155 policy, #156 CLI ref (#61). PR for #60/#62 open. #145 PR waits for fast-set bench.
108
+ - 2026-10-25 PO: milestones reshuffled: v0.2.8 = release now (#144 #145 + sandbox venv + CLI/providers docs), v0.2.9 = docs overhaul (#150-#154, #63-#66), v0.2.10 = #27 #79 #132-#137. Merged: #146 #148 #149 #155 #156 #157 #158. Release PR v0.2.8 (version bump, notes) prepared; GitHub Release only on PO yes.
109
+ - 2026-10-25 RELEASED v0.2.8 'Room to Answer' (release PR #159 -> f4370b1, GitHub Release, delivery.yml success, PyPI tether-sdk 0.2.8 live, milestone closed). Docs v0.2.9 started: #151 site structure PR (nav = Start here/Guides/Concepts/Reference/Help, 'For:' line per page, CONTRIBUTING.md replaces docs/testing.md + releasing.md, tests/test_docs_structure.py). Lesson: ruff format --check also formats Python blocks in docs; renamed anchors break the strict mkdocs build via old release-notes links -> run both before pushing docs.
110
+ - 2026-10-25 PO: 'merge all docs PRs and cut the next version'. Docs plan (#150) done: #155 #156 #157 #160 #161 #162 #165 #166 #167 merged, epic closed. Found #163 while writing guide 1 (qwen3.5:9b fixes the test, passes, never calls done -> FAILED Stalled); #164 merged on PO yes (Rule 3 reading: passing verify gates at stall time -> COMPLETED). Release PR v0.2.9 prepared. Next: v0.2.10 = #27 #79 #132-#137 (8 issues; pick by evidence, e.g. bench failure breakdown after v0.2.9). Tether friction this stretch: docs rewrites by Nemotron invent API facts and end without done; harness.py cards need 40+ steps.
@@ -0,0 +1,85 @@
1
+ # Work on v0.2.4
2
+ - Slug: work-on-v0-2-4
3
+ - Status: done
4
+ - Started: 2026-10-20 Updated: 2026-10-20 Closed: 2026-10-21
5
+ - Branches / PRs: worktree branch `claude/caveman-full-3e3119` (base main @ 8f0e0dd)
6
+
7
+ ## Goal
8
+ Work toward Tether v0.2.4 (follows v0.2.3 release, #94). Milestone v0.2.4: #88, #85, #75, #74.
9
+
10
+ ## Requests
11
+ - 2026-10-20: `/keep-feature-context new work-on-v0.2.4` — start log for v0.2.4 work.
12
+
13
+ ## Decisions
14
+ - 2026-10-20: SWE = tether headless, model `nvidia/nvidia/nemotron-3-ultra-550b-a55b` (provider `nvidia` in ~/.tether/providers.yaml, key NVIDIA_API_KEY from ~/.profile). Verify gates: ruff, mypy, pytest cov 100. 3 parallel worktrees (#75+#74 share harness loop so one session).
15
+ - 2026-10-20: Session runs with caveman (full) + ponytail (full) modes; code/commits/PRs written normal.
16
+
17
+ ## Problems
18
+
19
+ ## Problems
20
+ - 2026-10-20: 3 parallel nemotron sessions all hit NVIDIA HTTP 429 (3 retries). Run sequentially.
21
+ - 2026-10-20: #88 ses_c488b7de resumed: 93/80 steps (max_steps overshoot = #75), 0 edits, only reads/sed. Retry ses_eee3fb0f with exact plan: 60/60 steps, FAILED, tree clean; last cmd `edit replace ... --lines 62:62` (invalid syntax guess). Nemotron-3-ultra via tether not landing edits; likely needs `edit --help` discipline or stronger model.
22
+
23
+ ## Progress log
24
+ - 2026-10-20: Log created. Existing related log: `active/v0-2-bugs.md`.
25
+
26
+ - 2026-10-20: Milestone v0.2.4 = #88, #85, #75, #74 (all bugs). Launched: #88 ses_c488b7de (~/worktrees v024-88, fix/88-provider-deadline); #85 ses_b5cc20de (v024-85, fix/85-stale-running); #75+#74 ses_008272e8 (v024-75-74, fix/75-74-maxsteps-done-nudge). Worktrees under .claude/worktrees/.
27
+
28
+ - 2026-10-20 FINDINGS (dogfooding nemotron-3-ultra via tether, runs ses_c488b7de/eee3fb0f/2eaaba60/760137c4):
29
+ 1. Model NEVER used the `stdin` param (0 of 150+ turns); wrote heredocs/quoted text in `cmd` -> `edit replace` rejected 4x. FIX COMMITTED: a61b312 on branch fix/heredoc-stdin (worktree v024-88): multiplexer turns trailing heredoc in cmd into stdin (not for bash). Tests 100% cov, docs updated. After fix model did land an edit (first time).
30
+ 2. Read thrash: model cycles ollama->anthropic->openai->base->test files (period-5). `live_reads` MAX_LIVE_READS=4 < 5 files -> LRU thrash, each re-read evicts next. `detect_cycle` only catches 2-gram x3 / 3-gram x2, window 8 -> never fires. Raising active_char_cap 2400->8000 did NOT help (27/46 repeat cmds); reverted.
31
+ 3. NVIDIA free tier 429s even sequentially; `post_with_retry` retries 2x with 1s,2s backoff, no Retry-After -> sessions die FAILED (ses_760137c4 at 46/60).
32
+ 4. max_steps overshoot (93/80) after `send` resume = #75; no done nudge = #74.
33
+ 5. gh needs auth inside sandbox (GH_TOKEN env dropped) -> model cannot read issues; paste issue body into goal.
34
+ Ideas: detect_cycle n up to 5 w/ window 12; MAX_LIVE_READS 4->8 (or scale with budget); 429 honors Retry-After + longer backoff; completion/explore-budget nudge (#74).
35
+
36
+ - 2026-10-21 PRESET SEARCH (unscoped #88, nemotron-3-ultra, harness script scratchpad/exp.sh; all FAILED, 0 reached done):
37
+ | run | change | tokens | steps | result |
38
+ | ctrl x2 | none | 343-423k | 60 | 0 edit-tool calls, 8-20 repeats |
39
+ | A | skill text (bash prefix, stdin, edit flow) | 395k | 60 | no edits |
40
+ | B | fold-after 8, ctx 32k | 368k | 60 | no edits |
41
+ | C0/C1 | SEARCH/REPLACE edit tool (+skill) | 403k/422k | 60 | edited 3-4 files via bash patch scripts at step ~55, unfinished |
42
+ | D | C1 + 120 steps | 784k | 101 | died on 429; still re-reading at 101 |
43
+ | E | obs cap 8000 + fold 8 + ctx 32k + skill | 447k | 60 | 39 repeats, no edit |
44
+ Replay of stuck step 58: model reasoning = 'now implement' but action = `cat base.py` again; echoing reasoning_content back did NOT change it (4/4 still cat). Observations fully visible (8099 chars, not elided). Knobs (fold, cap, ctx, steps, skill text) do not fix; only SCOPED goals (file+range+exact plan) produced edits (ses_8a959866).
45
+ Committed on branch fix/88-provider-deadline (worktree v024-88), all 100% cov: heredoc->stdin; 429 Retry-After + 5 attempts; MAX_LIVE_READS 8; reads keyed by path+range; .py parse warning on edit; SEARCH/REPLACE blocks.
46
+
47
+ - 2026-10-21 #85 SCOPED BRIEF WORKS: brief = scope (file+methods), numbered plan, test spec, run cmd (scratchpad/goal85.txt, exp3.sh, skill C). ses_acb4e576: 40 steps, 214k tokens, correct `_reap_dead` + test, but hit max_steps before done. Gaps I fixed by hand: PermissionError (other-user pid = alive; my plan omitted it), test_agent_interface fake-RUNNING session needed pid=os.getpid(), release notes/AGENTS.md. Committed ef08560 on fix/85-reap-dead-worker (from main, clean for PR). Model diff saved scratchpad/nemotron-85.diff.
48
+ Lessons: scoped brief >> any knob; brief must list edge cases/existing tests that interact; give 50% more steps than the plan needs (it burned ~12 steps on test/doc fiddling via python-heredoc rewrites).
49
+
50
+ - 2026-10-21 #88 via scoped brief: ses_b251069e, 32 steps, 126k tokens, correct first pass (wait_for + test + docs). Session FAILED only from gate_error: verify gate used `uv run` but sandbox env has no uv on PATH -> use `.venv/bin/ruff|mypy|pytest` in --verify (exp3.sh updated). Rebased onto main as fix/88-attempt-deadline, PR #101. Brief template that works: scope+files, numbered plan with exact lines/strings, indentation warning, test spec naming helpers to reuse/avoid, docs bullets, run cmd, done. Skill C (SEARCH/REPLACE hint) used.
51
+ - 2026-10-21 #74 brief (done-nudge: is_quiet() + QUIET_NUDGE_STEPS=6 one-shot [NUDGE] appended to observation) running as ses via exp3.sh F74. #75 design pending: max_steps semantic = per-run budget; `step_limit = step_start + rec.max_steps` in execute_session (harness.py ~593) is why 46/40; need display fix in status.
52
+
53
+ - 2026-10-21 MERGED (squash, order #103,#96,#98,#101,#102,#99,#97,#100). Conflicts handled: release-notes (scratchpad/rn.py re-applies each PR's bullets onto main), AGENTS.md + tests appended by two PRs (kept both), golden snapshot drift on #97 and #100 reviewed + accepted (intended: heredoc step ok; parse warning/SEARCH-REPLACE). Gotcha: PR #97 head stuck stale after push; empty commit resynced (land.sh guards now). Gap found: golden suite did not exercise #99 -> PR #104 adds read_range_pingpong (verified: reverting #99 fails only that trace).
54
+ - #75 (PR #102) source change was nemotron's (scoped brief); #74 done-nudge not yet done (H74 rerun with all fixes in progress).
55
+
56
+ - 2026-10-21 DONE: #104 and #105 merged (#74 closed). Milestone v0.2.4 issues #74 #75 #85 #88 all CLOSED; main at ce72047. #74 nudge: nemotron wrote helper+loop wiring (50 steps), finished by hand (line wrap, coverage, AGENTS.md, golden trace done_nudge).
57
+
58
+ - 2026-10-21 PO REDIRECT: benchmark/baseline (Layer 2) dropped as unmaintainable (archived in scratchpad/bench-archive, branch feat/bench local only). Replaced by e2e: PR #106 `e2e/` (real CLI + fault-injecting proxy `e2e/proxy.py` in front of ollama `tether-ollama` container localhost:11435; models gemma4:e4b qwen3:8b qwen3-coder:30b qwen3.5:9b). 38 scenarios, `TETHER_E2E=1 uv run pytest e2e`, local only. Hard asserts on tether behaviour (any model), real-model success = soft warning. Mutation-checked (4 fixes reverted -> matching scenario red). PO rule added to AGENTS.md: run e2e locally before every merge, result in PR, mitigate every failure.
59
+ Gaps listed in docs/testing.md: sub-agents, pipelines, MCP, stats/retro/events/misses, other providers, web search, skill tools.py, --no-network, context budget #81.
60
+
61
+ - 2026-10-21 PO 'go ahead': merged #106 (e2e infra), then extended coverage in #107 -> 54 e2e scenarios (agents, pipeline, providers, MCP, web, skills tools.py, telemetry, --no-network, context budget), mutation-checked, e2e result 54 passed/91s. e2e rule in AGENTS.md satisfied (result in PR body).
62
+
63
+ ## Next steps
64
+ - [x] #75/#74/#88/#85 all merged
65
+ - [ ] v0.2.4 release PR (version bump + release notes heading `## v0.2.4 (2026-10-21)`), PO OK needed
66
+ - [x] e2e merged (#106, #107)
67
+ - [ ] v0.2.4 release PR (version bump, dated release notes); PO wanted a green regression run first: e2e 54/54 is that. Needs PO go-ahead
68
+ - [ ] Remaining e2e gaps listed in docs/testing.md; cleanup worktrees/branches (ask PO)
69
+ - [ ] Clean up merged branches + worktrees (v024-*, exp-*, gold-demo) - ask PO
70
+ - [x] (all merged 2026-10-21 except #104) PRs opened 2026-10-21: #96 (#85 reap dead worker), #97 heredoc->stdin, #98 429 retry, #99 reads per range+window 8, #100 edit parse warning + SEARCH/REPLACE. Old local branch fix/88-provider-deadline (8 commits) superseded, unpushed.
71
+ - [ ] Merge order matters for docs/release-notes.md (each adds under '## v0.2.4 (unreleased)'; later PRs need trivial rebase)
72
+ - [ ] Watch CI on #96-#100
73
+ - [ ] Release notes v0.2.4 + release PR
74
+
75
+ ## Sessions
76
+ | Date | Session note |
77
+ | 2026-10-20 | Created in worktree caveman-full-3e3119 |
78
+
79
+ ## Wrap-up
80
+ - Outcome: v0.2.4 RELEASED. Release PR #108 merged (05bcf15), GitHub Release v0.2.4 'Regression Safety Net', delivery.yml success, PyPI tether-sdk 0.2.4 live, milestone v0.2.4 closed (#74 #75 #85 #88 all closed).
81
+ - Shipped PRs: #96 (#85), #97 heredoc->stdin, #98 429 retry, #99 reads per range + window 8, #100 edit parse warning + SEARCH/REPLACE, #101 (#88), #102 (#75), #103 golden traces, #104 ping-pong golden, #105 (#74 done nudge), #106 + #107 e2e (54 scenarios), #108 release.
82
+ - Final decisions: bench/baseline approach dropped as unmaintainable; regression strategy = golden traces in CI (deterministic, snapshot diffs) + local e2e behind a fault-injecting ollama proxy (assert tether behaviour, never model skill). AGENTS.md rule: run e2e locally before every merge, result in PR, mitigate every failure.
83
+ - Findings on using tether with nemotron-3-ultra: token knobs (fold, caps, ctx, steps, skill text) do not help on unscoped tasks in a big repo (340-780k tokens, no finish); scoped briefs (file + exact plan + test spec + edge cases) finish (#88: 32 steps/126k tokens; #85: 40/214k). On a tiny repo an unscoped task passes in 6 steps/4k tokens (repo size + exploration is the cost). Models write edits via bash heredocs/patch scripts; the `edit` tool needed tolerance (heredoc, unterminated SEARCH). Verify gates must use `.venv/bin/*` (no uv on sandbox PATH). NVIDIA free tier 429s need Retry-After + longer backoff.
84
+ - Follow-ups / debt: e2e gaps in docs/testing.md (pipeline verify gates/model routing, `mem pin --project`, `retro --apply`, Anthropic caching); the 'coding preset' idea became 'scoped brief template' (not shipped as a skill/file); main checkout /home/walkdead/Projects/tether is behind origin/main (not touched); PR bodies for #96..#108 mention nemotron-written pieces.
85
+ - Lessons: PR head can go stale after a push (empty commit resyncs; check headRefOid before trusting CI); golden suites need a trace per fix or the fix is unlocked (#99 gap); mutation-check every new test; `pkill -f` pattern can kill your own shell.
@@ -0,0 +1,12 @@
1
+ {
2
+ "tether_repo": "igormcsouza/tether",
3
+ "timeout_min": 15,
4
+ "tiers": {
5
+ "0": ["tether:nvidia/nvidia/nemotron-3-ultra-550b-a55b", "tether:nvidia/z-ai/glm-5.3", "opencode/nemotron-3-ultra-free"],
6
+ "1": ["opencode:anthropic/claude-haiku-5-5"],
7
+ "2": ["opencode:anthropic/claude-sonnet-5-5"]
8
+ },
9
+ "context": {"nvidia/nvidia/nemotron-3-ultra-550b-a55b": 128000, "nvidia/z-ai/glm-5.3": 128000},
10
+ "sensitive": [{"path": ".github/**", "min_tier": 2}, {"path": "tether/sandbox.py", "min_tier": 2}],
11
+ "verified": {}
12
+ }
@@ -46,7 +46,7 @@ Reviewers and the Team Leader cite the failing line when they reject a change.
46
46
  - A task only completes when the agent explicitly calls `act("done", stdin="<final deliverable>")` (or `act("done '<short answer>'")`), pauses for human/parent input via `act("done --ask", stdin="<question>")` (transitioning the session to `WAITING_INPUT` and releasing the worker process until resumed via `send`), or hits `max_steps`.
47
47
  - If the model emits plain text without calling `act`, the harness appends a brief deterministic nudge reminding it to either execute a command or call `done`.
48
48
  - After 6 consecutive read-only/verification steps following a change, the harness appends a one-shot `[NUDGE]` to that step's observation reminding the model to call `done` if the task is complete (0 static prompt tokens, #74). Before any change, 12 read-only steps in a row (then every 8 more) append a one-line `[NUDGE]` to make the edit or call `done` (#127). Seven reads of one file in a row with no change are a `cycle_stall`, and 4 stall warnings without a change end the session `FAILED` as `Stalled` (#92); `tether stop <id>` terminates a detached worker (#89).
49
- - When `verify` gate commands are configured (via `Harness(verify=[...])`, CLI `--verify`, or Skill YAML `verify: [...]`), `Harness.execute_session` deterministically executes each command inside the session's `SandboxPolicy` before allowing `done` to transition to `COMPLETED` (consuming 0 static prompt tokens until a gate fails). A gate that errors instead of failing (sandbox violation, exit 124/126/127) ends the session `FAILED` at once as `gate_error` ("gate misconfigured"), without counting toward the consecutive-failure abort.
49
+ - When `verify` gate commands are configured (via `Harness(verify=[...])`, CLI `--verify`, or Skill YAML `verify: [...]`), `Harness.execute_session` deterministically executes each command inside the session's `SandboxPolicy` before allowing `done` to transition to `COMPLETED` (consuming 0 static prompt tokens until a gate fails). A gate that errors instead of failing (sandbox violation, exit 124/126/127) ends the session `FAILED` at once as `gate_error` ("gate misconfigured"), without counting toward the consecutive-failure abort. When the stall guard is about to end a session as `Stalled` and gates are configured, it runs them first: a change was made and every gate passes, so the session ends `COMPLETED` ("Finished by the harness"), since the deterministic gate is the completion criterion the caller asked for (#163).
50
50
 
51
51
  ### Rule 4: Progressive `--help` (JIT Schema Disclosure)
52
52
  - The system prompt lists at most **1 line per enabled tool namespace** (`- <name>: <short summary>`, target **≤ 12 tokens per entry**).
@@ -206,11 +206,15 @@ uv run mypy tether/
206
206
  - All model calls and I/O-bound tool executions must be `async`/`await` native, while seamlessly wrapping synchronous user `@tool` functions.
207
207
  3. **Graceful Degradation on 9B Hallucinations:**
208
208
  - Small models occasionally emit `cmd` with minor quirks (e.g., leading `$`, wrapping backticks, or calling a tool name directly instead of `act`). The multiplexer must normalize trivial syntax quirks deterministically before failing. This includes unescaping literal `\n`/`\t` in one-line `stdin` for `edit write`/`edit replace` and `done` (never `bash`), turning a trailing shell heredoc in `cmd` (`edit write f <<'EOF' ... EOF`) into `stdin` (never for `bash`), unwrapping `bash -c/-lc '<cmd>'` and `sh -c` wrappers, running an unknown first word through the enabled `bash` tool (never for disabled built-ins), registering extra quirk fixers with `register_normalizer`, mapping a native tool call named other than `act` to `<name> --k 'v'` so the JIT usage answers it, inferring the `edit` verb (`edit <path>` -> view/replace/write) and accepting `apply_patch` (`*** Begin Patch` or unified-diff patches, also when a diff arrives as `edit <path>` stdin) as an `edit` verb.
209
- 4. **Golden traces:** behaviour the model sees (framing, folding, nudges, tool output) is locked by `tests/golden/*.snap.json`. A PR that changes it runs `UPDATE_GOLDEN=1 pytest tests/test_golden.py` and the snapshot diff is part of the review; unrelated traces must not change. See `docs/testing.md`.
210
- 5. **E2E scenarios:** every feature or bug fix ships with a scenario in `e2e/` (real CLI, real ollama behind a fault-injecting proxy, local only, `TETHER_E2E=1 uv run pytest e2e`). Assert on what tether sends and records, never on the model's skill; script the reply or inject the fault so the test does not depend on model potency. **Before merging any PR, run `TETHER_E2E=1 uv run pytest e2e` locally and put the result in the PR description (CI cannot run it). Every failure must be mitigated before merge: fix the code, or fix a wrong scenario, or record in the PR why it is acceptable and what follows up. A PR is not merged with an unexplained red scenario.** See `docs/testing.md`.
209
+ 4. **Golden traces:** behaviour the model sees (framing, folding, nudges, tool output) is locked by `tests/golden/*.snap.json`. A PR that changes it runs `UPDATE_GOLDEN=1 pytest tests/test_golden.py` and the snapshot diff is part of the review; unrelated traces must not change. See `CONTRIBUTING.md`.
210
+ 5. **E2E scenarios:** every feature or bug fix ships with a scenario in `e2e/` (real CLI, real ollama behind a fault-injecting proxy, local only, `TETHER_E2E=1 uv run pytest e2e`). Assert on what tether sends and records, never on the model's skill; script the reply or inject the fault so the test does not depend on model potency. **Before merging any PR, run `TETHER_E2E=1 uv run pytest e2e` locally and put the result in the PR description (CI cannot run it). Every failure must be mitigated before merge: fix the code, or fix a wrong scenario, or record in the PR why it is acceptable and what follows up. A PR is not merged with an unexplained red scenario.** See `CONTRIBUTING.md`.
211
211
  6. **Documentation Integrity:**
212
212
  - Keep `README.md` and `AGENTS.md` synchronized whenever architectural interfaces or built-in tool signatures change.
213
213
  - **Always update documentation in the same PR** when introducing a new feature, changing an existing behavior, or altering a CLI/SDK interface. This covers `README.md`, `AGENTS.md`, the MkDocs pages under `docs/` (including `docs/reference/*` for new modules), and a `docs/release-notes.md` entry. A change without matching docs is incomplete.
214
+ - **Two audiences, two jobs.** Every doc change is judged against the one it serves:
215
+ - **Docs site (`docs/`, mkdocs on GitHub Pages)** is for people who *use* tether as a tool and for agents that integrate it. It explains how tether works and how to get a job done, in plain language, with a story and a real, re-runnable example per guide (command + real output). It does **not** carry our bug history ("fixed in vX"), half-finished work, internal experiments or stale benchmarks; a known problem is a link to its GitHub issue (label `known-issue`). Contributor material (golden traces, releasing) lives in `CONTRIBUTING.md`, not in the user nav. Each page opens with who it is for and what you can do after reading it. One canonical page per topic (e.g. providers); everything else links to it, nothing is copied.
216
+ - **`README.md`** is for people evaluating tether, building their own harness on it, or contributing: why tether is interesting (the **current** benchmark, regenerated each release by `bench/report.py`), the architecture and *why this and not the alternative*, a short install + first run, and how to contribute. It points to the docs site for everything else and stays short (target ~150 lines).
217
+ - The step plan is tracked in epic #150; a docs PR names the step it completes.
214
218
 
215
219
  ## Dev team specifics
216
220
  - Stack: Python 3.12+, package `tether/`, tests in `tests/`, docs in `docs/` (MkDocs); `uv`, ruff, mypy
@@ -218,6 +222,8 @@ uv run mypy tether/
218
222
  - E2E / QA: `e2e/` scenarios (real CLI + ollama behind a fault-injecting proxy, local only); shared resource: the `tether-ollama` container (port 11435)
219
223
  - Branches/commits/PRs: Conventional Commits (`feat(scope): ... (#N)`, `release: vX.Y.Z ...`); PR per task, squash-merged to `main`; docs updated in the same PR (see section 5.4)
220
224
  - Delivery: PR per task
221
- - Hard stops (ask first): force push / history rewrite
225
+ - Hard stops (ask first): force push / history rewrite; merging a PR and cutting a release need the PO's explicit yes each time
222
226
  - Design docs: `AGENTS.md` sections 1-3, `docs/architecture.md`, `docs/reference/*`
223
- - feature-context store: .claude/feature-context/
227
+ - Orchestration: **`/gru` runs this repo** (Team Leader + router). Strong model plans, writes the failing acceptance tests first, reviews and decides; tether does the typing as the minion at Tier 0 on the strongest free model (`nvidia/nvidia/nemotron-3-ultra-550b-a55b`, fallback `nvidia/z-ai/glm-5.3`), escalating one tier only on evidence. Tiers, context sizes and sensitive paths: `.claude/gru.json`. tether's own failures while doing a card are logged as friction and filed as issues (with the PO's OK).
228
+ - Improvement loop: **every PR leaves tether a little better**, measured, not asserted: a behaviour change ships with a bench or e2e delta (Polyglot-Python fast set on `ollama/qwen3.5:9b`, `bench/`) in the PR body, reported honestly even when it is flat. After a merge, gru re-reads the next planned milestone and the other open bug issues and picks the one that clearly improves tether most (evidence from bench failure breakdowns and `tether stats` friction beats guesses); features and docs wait behind bugs that cost steps or pass rate.
229
+ - gru store: .claude/gru/ (committed; legacy `feature-context` logs were moved here)
@@ -1,4 +1,24 @@
1
- # Testing: golden traces
1
+ # Contributing to tether
2
+
3
+ Thanks for helping. Tether stays **lightweight, reliable, extensible, model-agnostic, easy to use, resourceful and a token saver**: that list (the *Philosophy Gate*) and the architectural rules live in [AGENTS.md](AGENTS.md), which is the authoritative guide for contributors and coding agents. Read its sections 1-3 before changing behaviour.
4
+
5
+ ## Setup and checks
6
+
7
+ ```bash
8
+ uv sync # environment
9
+ uv run ruff check . && uv run ruff format --check . # lint and format (also formats Python in docs)
10
+ uv run mypy tether/ # types
11
+ uv run pytest --cov=tether --cov-report=term-missing --cov-fail-under=100 # unit tests, 100% coverage (CI)
12
+ TETHER_E2E=1 uv run pytest e2e # e2e, local only (needs the tether-ollama container)
13
+ ```
14
+
15
+ ## Pull requests
16
+
17
+ - One PR per task, Conventional Commits (`feat(scope): ... (#N)`, `fix(...)`, `docs(...)`, `release: vX.Y.Z ...`), squash-merged to `main`.
18
+ - Update the docs in the same PR (README, the MkDocs pages, `docs/release-notes.md`); see *Two audiences, two jobs* in AGENTS.md section 5.6 for what belongs where.
19
+ - A behaviour change carries a measured result in the PR body (bench or e2e delta), reported honestly even when it is flat. Put the `TETHER_E2E=1 uv run pytest e2e` result in the PR; CI cannot run it.
20
+
21
+ ## Testing: golden traces, e2e scenarios and the model bench
2
22
 
3
23
  Tether is a deterministic envelope around a random model, so a change to framing, folding,
4
24
  nudges, tools or retries can silently change what the model is shown. Golden traces make that
@@ -20,7 +40,7 @@ Shipped traces: a real researcher run (web stubbed, plain-text `done` nudges), a
20
40
  coding run covering the edit failure modes seen with small models, and a `done --ask` /
21
41
  `send` resume, and a range ping-pong (alternating views of one file; the latest read of each range stays unfolded, older ones fold). Add one for every behaviour that must not regress.
22
42
 
23
- ## End-to-end scenarios (local, real processes, real ollama)
43
+ ### End-to-end scenarios (local, real processes, real ollama)
24
44
 
25
45
  `e2e/` drives the real `tether` CLI in a throwaway workspace. A small fault-injecting proxy
26
46
  (`e2e/proxy.py`) sits between tether and ollama, so a scenario can force the situation instead of
@@ -83,7 +103,7 @@ judge (answer quality).
83
103
  **Rule:** a new feature or bug fix ships with a scenario here. If a model must misbehave to
84
104
  trigger it, script the reply; if infrastructure must fail, add a fault to the proxy.
85
105
 
86
- ## Model conformance bench (developers only)
106
+ ### Model conformance bench (developers only)
87
107
 
88
108
  `bench/` holds nine tasks (the `focus` task checks that an exact single-file goal is not lost in a distractor-heavy repo) with hidden-test graders and three runners (Tether, a plain tool loop,
89
109
  Claude Code) so the same model can be compared across harnesses and releases. It needs real
@@ -91,3 +111,14 @@ models, so it is not in CI and not in the package: use it when onboarding a mode
91
111
  release to see friction that scripted tests cannot (the shell-wrapper, bare-command and
92
112
  tool-name failures behind #109 were found this way). Anything it finds that can be scripted
93
113
  becomes a unit, golden or e2e test. See `bench/README.md`.
114
+
115
+ ## Releasing
116
+
117
+ PyPI is published only from a GitHub Release, never from a push or tag.
118
+
119
+ 0. Re-run the commands in `docs/guides/` against the release candidate and fix any output that changed.
120
+ 1. Bump `__version__` in `tether/__init__.py` (and the version assertion in `tests/test_tether.py`) and update `docs/release-notes.md`.
121
+ 2. Merge to `main`.
122
+ 3. Create a GitHub Release with tag `v<version>` (for example `v0.1.0`). The tag must match `__version__` (a leading `v` is ignored) or the workflow fails before building.
123
+
124
+ The `delivery.yml` workflow then verifies the tag, builds the sdist and wheel, publishes to PyPI with trusted publishing (no secrets) and attaches both files to the release. Pre-releases are skipped: nothing is published or attached.
@@ -0,0 +1,143 @@
1
+ Metadata-Version: 2.5
2
+ Name: tether-sdk
3
+ Version: 0.2.9
4
+ Summary: General-purpose, headless-first LLM-Native micro-harness for small language models
5
+ Project-URL: Homepage, https://github.com/igormcsouza/tether
6
+ Project-URL: Repository, https://github.com/igormcsouza/tether
7
+ Project-URL: Documentation, https://igormcsouza.github.io/tether/
8
+ Author-email: Igor Souza <igormcsouza@gmail.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: agents,cli,harness,llm,slm,sqlite
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Requires-Python: >=3.12
16
+ Requires-Dist: httpx>=0.27.0
17
+ Requires-Dist: pyyaml>=6.0.1
18
+ Provides-Extra: mcp
19
+ Requires-Dist: mcp<3,>=2.0; extra == 'mcp'
20
+ Description-Content-Type: text/markdown
21
+
22
+ # 🪢 Tether
23
+
24
+ **A small, headless-first harness that lets small local models (and frontier ones) do real work with a tiny prompt.**
25
+
26
+ [![PyPI](https://img.shields.io/pypi/v/tether-sdk?color=0d9488&label=PyPI%20%7C%20tether-sdk)](https://pypi.org/project/tether-sdk/)
27
+ [![Docs](https://img.shields.io/badge/Docs-igormcsouza.github.io%2Ftether-0d9488)](https://igormcsouza.github.io/tether/)
28
+ [![Python](https://img.shields.io/badge/Python-3.12%2B-3b82f6)](#install-and-first-run)
29
+ [![Models](https://img.shields.io/badge/Models-Ollama%20%7C%20OpenAI--compatible%20%7C%20Claude-10b981)](https://igormcsouza.github.io/tether/reference/providers/)
30
+
31
+ ```bash
32
+ uv tool install tether-sdk
33
+ tether run --model ollama/qwen3.5:9b --tools bash,edit --verify "pytest -q" "fix the failing tests"
34
+ ```
35
+
36
+ ## Why Tether
37
+
38
+ Most agent frameworks treat the context window as a dumping ground. Before your task is read, they inject **3,000 to 8,000 tokens** of JSON tool schemas and system prompt, then append every tool output forever. On a frontier model that is money. On a 9B model running on your laptop it is fatal: attention is diluted, small models fumble nested JSON, and changing the tool list between turns throws away the inference server's KV cache.
39
+
40
+ Tether is built the other way round:
41
+
42
+ - **One tool, not thirty.** The model sees a single `act(cmd, stdin)` schema. Everything else (`bash`, `edit`, `web`, `mem`, your own functions) is a command behind it, off by default. Fixed framing is under 150 tokens.
43
+ - **Old output folds away.** Tool results stay in full for two turns, then become a one-line tombstone. Everything lives in SQLite and comes back by search.
44
+ - **The envelope is deterministic.** Sandboxing, state, step limits, verification gates and termination are plain code. The model only reasons; it is never trusted with safety.
45
+
46
+ ## How well does it work
47
+
48
+ Tether answers to one number: how many real coding exercises a small local model finishes. On the Polyglot-Python set (Aider's 34 Python exercises, graded by each exercise's own tests), `qwen3.5:9b` through Ollama, 12-exercise fast set, 2 trials each:
49
+
50
+ | | v0.2.7 | v0.2.8 |
51
+ |---|---|---|
52
+ | Passes | 10 of 24 | 11 of 24 |
53
+ | Mean score | 0.741 | 0.756 |
54
+ | "Tool call cut off" hints | 29 | 2 |
55
+ | Steps that did nothing | 19% | 2.2% |
56
+
57
+ One run is noisy (about 0.1), so read the pass count and the failure breakdown, not one decimal. Method, how to reproduce it and fair-comparison rules: [Benchmarks](https://igormcsouza.github.io/tether/benchmarks/). Every change that touches model-visible behaviour has to move this number or leave it alone.
58
+
59
+ ## How it works
60
+
61
+ ```mermaid
62
+ flowchart LR
63
+ You["CLI · SDK · MCP"] --> Loop
64
+ subgraph Envelope["Deterministic envelope"]
65
+ Loop["bounded loop<br/>steps · stall guard · gates"] --> Mux["act(cmd, stdin)<br/>command bus"]
66
+ Mux --> Sand["sandbox<br/>bwrap · workspace jail"]
67
+ Sand --> Tools["bash · edit · web · mem · agent · your @tool"]
68
+ Tools --> Fold["fold old output"]
69
+ Fold --> DB[("SQLite WAL + FTS5<br/>.tether/tether.db")]
70
+ DB --> Loop
71
+ end
72
+ Loop <-->|"messages"| Model["LLM<br/>ollama · openai · anthropic"]
73
+ ```
74
+
75
+ A session is a row in SQLite, so it survives crashes, runs detached (`--headless`), takes new instructions while running (`tether send`), and can be read by another agent as compact JSON. A task ends only when the model calls `done`, after your `--verify` commands pass.
76
+
77
+ ## Why this and not that
78
+
79
+ | Decision | Instead of | Why |
80
+ |---|---|---|
81
+ | One `act` tool, commands behind it | A JSON schema per tool | CodeAct and SWE-agent results: one executable channel beats many schemas, most for 7-9B models; and the prompt prefix never changes, so the KV cache survives. |
82
+ | Progressive `--help` | Full usage up front | A tool costs about a dozen tokens until the model asks or gets it wrong. |
83
+ | SQLite (WAL, FTS5) as memory | An ever-growing transcript | Context stays a bounded working set; the rest is searchable. State is ACID, so sessions resume and agents share results. |
84
+ | Kernel sandbox (`bwrap`), env scrubbing, SSRF guard | "Please be careful" in the prompt | Safety that depends on the model obeying is not safety. |
85
+ | Explicit `done` plus verification gates | Letting the model declare success | Small models stop early or never stop. The gate is a command you wrote. |
86
+ | Thin `httpx` adapters, 2 runtime dependencies | Vendor SDKs, LangChain-style frameworks | Easy to read, easy to add a backend (`providers.yaml`, no code), nothing to upgrade around. |
87
+
88
+ The research behind it: Maia et al. (2026) on probabilistic core and deterministic envelope, Wang et al. (2024, CodeAct), Yang et al. (2024, SWE-agent) and Packer et al. (2023, MemGPT); see [References](#references) and [Architecture](https://igormcsouza.github.io/tether/architecture/).
89
+
90
+ ## Install and first run
91
+
92
+ ```bash
93
+ uv tool install tether-sdk # or: pip install tether-sdk
94
+ ollama pull qwen3.5:9b # any model works; see the providers page
95
+ tether run --model ollama/qwen3.5:9b --tools bash,edit "create hello.txt containing hi"
96
+ ```
97
+
98
+ Everything else (headless sessions, skills, pipelines, MCP, the CLI reference, writing your own tool or provider) is in the docs: **[igormcsouza.github.io/tether](https://igormcsouza.github.io/tether/)**. Start with the guides: [fix a failing test](https://igormcsouza.github.io/tether/guides/fix-a-failing-test/), [use it from Claude Code or Codex](https://igormcsouza.github.io/tether/guides/use-tether-from-your-agent/).
99
+
100
+ ## Build on it
101
+
102
+ ```python
103
+ import asyncio
104
+
105
+ from tether import Harness, tool
106
+
107
+
108
+ @tool(name="price", description="Look up the unit price of a fruit")
109
+ def price(fruit: str) -> str:
110
+ return f"{fruit}: 0.50 EUR"
111
+
112
+
113
+ async def main() -> None:
114
+ harness = Harness(model="ollama/qwen3.5:9b", tools=[price])
115
+ session = await harness.run("What does an apple cost?")
116
+ print(session.result)
117
+
118
+
119
+ asyncio.run(main())
120
+ ```
121
+
122
+ `Harness`, `Pipeline`, `Skill`, `SandboxPolicy`, `@tool` and `register_provider` are the public surface. The agent-facing JSON and the optional `tether mcp` server (`tether-sdk[mcp]`) are specified in the [reference](https://igormcsouza.github.io/tether/reference/agent-interface/).
123
+
124
+ ## Contributing
125
+
126
+ Tether stays lightweight, reliable, extensible, model-agnostic, easy to use, resourceful and a token saver; a change that fails one of those lines is reworked. Read [AGENTS.md](AGENTS.md) (the rules and the module map) and [CONTRIBUTING.md](CONTRIBUTING.md) (setup, checks, golden traces, e2e, the bench, releasing). Open an issue before a large change; small fixes with a test and a docs line are welcome as they are.
127
+
128
+ ```text
129
+ tether/ harness · multiplexer · context · store · sandbox · providers/ · tools/
130
+ tests/ unit, golden traces (what the model sees), 100% coverage
131
+ e2e/ real CLI and real Ollama behind a fault-injecting proxy (local)
132
+ bench/ Polyglot-Python and model checks (developers)
133
+ docs/ the user site (MkDocs)
134
+ ```
135
+
136
+ ---
137
+
138
+ ## References
139
+
140
+ 1. **Maia, P. H. M., et al. (2026).** *LLM-Native Applications as a Paradigm for AI-Driven Software Architecture*.
141
+ 2. **Wang, X., Chen, Y., Yuan, L., Zhang, Y., Li, Y., Peng, H., & Ji, H. (2024).** *Executable Code Actions Elicit Better LLM Agents (CodeAct)*. In **Proceedings of the 41st International Conference on Machine Learning (ICML 2024)**. [arXiv:2402.01030](https://arxiv.org/abs/2402.01030)
142
+ 3. **Yang, J., Jimenez, C. E., Wettig, A., Lieret, K., Yao, S., Narasimhan, K., & Press, O. (2024).** *SWE-agent: Agent-Computer Interfaces Enable Automated Software Engineering*. In **Advances in Neural Information Processing Systems (NeurIPS 2024)**. [arXiv:2405.15793](https://arxiv.org/abs/2405.15793)
143
+ 4. **Packer, C., Wooders, S., Lin, K., Fang, V., Patil, S. G., Stoica, I., & Gonzalez, J. E. (2023).** *MemGPT: Towards LLMs as Operating Systems*. [arXiv:2310.08560](https://arxiv.org/abs/2310.08560)
@@ -0,0 +1,122 @@
1
+ # 🪢 Tether
2
+
3
+ **A small, headless-first harness that lets small local models (and frontier ones) do real work with a tiny prompt.**
4
+
5
+ [![PyPI](https://img.shields.io/pypi/v/tether-sdk?color=0d9488&label=PyPI%20%7C%20tether-sdk)](https://pypi.org/project/tether-sdk/)
6
+ [![Docs](https://img.shields.io/badge/Docs-igormcsouza.github.io%2Ftether-0d9488)](https://igormcsouza.github.io/tether/)
7
+ [![Python](https://img.shields.io/badge/Python-3.12%2B-3b82f6)](#install-and-first-run)
8
+ [![Models](https://img.shields.io/badge/Models-Ollama%20%7C%20OpenAI--compatible%20%7C%20Claude-10b981)](https://igormcsouza.github.io/tether/reference/providers/)
9
+
10
+ ```bash
11
+ uv tool install tether-sdk
12
+ tether run --model ollama/qwen3.5:9b --tools bash,edit --verify "pytest -q" "fix the failing tests"
13
+ ```
14
+
15
+ ## Why Tether
16
+
17
+ Most agent frameworks treat the context window as a dumping ground. Before your task is read, they inject **3,000 to 8,000 tokens** of JSON tool schemas and system prompt, then append every tool output forever. On a frontier model that is money. On a 9B model running on your laptop it is fatal: attention is diluted, small models fumble nested JSON, and changing the tool list between turns throws away the inference server's KV cache.
18
+
19
+ Tether is built the other way round:
20
+
21
+ - **One tool, not thirty.** The model sees a single `act(cmd, stdin)` schema. Everything else (`bash`, `edit`, `web`, `mem`, your own functions) is a command behind it, off by default. Fixed framing is under 150 tokens.
22
+ - **Old output folds away.** Tool results stay in full for two turns, then become a one-line tombstone. Everything lives in SQLite and comes back by search.
23
+ - **The envelope is deterministic.** Sandboxing, state, step limits, verification gates and termination are plain code. The model only reasons; it is never trusted with safety.
24
+
25
+ ## How well does it work
26
+
27
+ Tether answers to one number: how many real coding exercises a small local model finishes. On the Polyglot-Python set (Aider's 34 Python exercises, graded by each exercise's own tests), `qwen3.5:9b` through Ollama, 12-exercise fast set, 2 trials each:
28
+
29
+ | | v0.2.7 | v0.2.8 |
30
+ |---|---|---|
31
+ | Passes | 10 of 24 | 11 of 24 |
32
+ | Mean score | 0.741 | 0.756 |
33
+ | "Tool call cut off" hints | 29 | 2 |
34
+ | Steps that did nothing | 19% | 2.2% |
35
+
36
+ One run is noisy (about 0.1), so read the pass count and the failure breakdown, not one decimal. Method, how to reproduce it and fair-comparison rules: [Benchmarks](https://igormcsouza.github.io/tether/benchmarks/). Every change that touches model-visible behaviour has to move this number or leave it alone.
37
+
38
+ ## How it works
39
+
40
+ ```mermaid
41
+ flowchart LR
42
+ You["CLI · SDK · MCP"] --> Loop
43
+ subgraph Envelope["Deterministic envelope"]
44
+ Loop["bounded loop<br/>steps · stall guard · gates"] --> Mux["act(cmd, stdin)<br/>command bus"]
45
+ Mux --> Sand["sandbox<br/>bwrap · workspace jail"]
46
+ Sand --> Tools["bash · edit · web · mem · agent · your @tool"]
47
+ Tools --> Fold["fold old output"]
48
+ Fold --> DB[("SQLite WAL + FTS5<br/>.tether/tether.db")]
49
+ DB --> Loop
50
+ end
51
+ Loop <-->|"messages"| Model["LLM<br/>ollama · openai · anthropic"]
52
+ ```
53
+
54
+ A session is a row in SQLite, so it survives crashes, runs detached (`--headless`), takes new instructions while running (`tether send`), and can be read by another agent as compact JSON. A task ends only when the model calls `done`, after your `--verify` commands pass.
55
+
56
+ ## Why this and not that
57
+
58
+ | Decision | Instead of | Why |
59
+ |---|---|---|
60
+ | One `act` tool, commands behind it | A JSON schema per tool | CodeAct and SWE-agent results: one executable channel beats many schemas, most for 7-9B models; and the prompt prefix never changes, so the KV cache survives. |
61
+ | Progressive `--help` | Full usage up front | A tool costs about a dozen tokens until the model asks or gets it wrong. |
62
+ | SQLite (WAL, FTS5) as memory | An ever-growing transcript | Context stays a bounded working set; the rest is searchable. State is ACID, so sessions resume and agents share results. |
63
+ | Kernel sandbox (`bwrap`), env scrubbing, SSRF guard | "Please be careful" in the prompt | Safety that depends on the model obeying is not safety. |
64
+ | Explicit `done` plus verification gates | Letting the model declare success | Small models stop early or never stop. The gate is a command you wrote. |
65
+ | Thin `httpx` adapters, 2 runtime dependencies | Vendor SDKs, LangChain-style frameworks | Easy to read, easy to add a backend (`providers.yaml`, no code), nothing to upgrade around. |
66
+
67
+ The research behind it: Maia et al. (2026) on probabilistic core and deterministic envelope, Wang et al. (2024, CodeAct), Yang et al. (2024, SWE-agent) and Packer et al. (2023, MemGPT); see [References](#references) and [Architecture](https://igormcsouza.github.io/tether/architecture/).
68
+
69
+ ## Install and first run
70
+
71
+ ```bash
72
+ uv tool install tether-sdk # or: pip install tether-sdk
73
+ ollama pull qwen3.5:9b # any model works; see the providers page
74
+ tether run --model ollama/qwen3.5:9b --tools bash,edit "create hello.txt containing hi"
75
+ ```
76
+
77
+ Everything else (headless sessions, skills, pipelines, MCP, the CLI reference, writing your own tool or provider) is in the docs: **[igormcsouza.github.io/tether](https://igormcsouza.github.io/tether/)**. Start with the guides: [fix a failing test](https://igormcsouza.github.io/tether/guides/fix-a-failing-test/), [use it from Claude Code or Codex](https://igormcsouza.github.io/tether/guides/use-tether-from-your-agent/).
78
+
79
+ ## Build on it
80
+
81
+ ```python
82
+ import asyncio
83
+
84
+ from tether import Harness, tool
85
+
86
+
87
+ @tool(name="price", description="Look up the unit price of a fruit")
88
+ def price(fruit: str) -> str:
89
+ return f"{fruit}: 0.50 EUR"
90
+
91
+
92
+ async def main() -> None:
93
+ harness = Harness(model="ollama/qwen3.5:9b", tools=[price])
94
+ session = await harness.run("What does an apple cost?")
95
+ print(session.result)
96
+
97
+
98
+ asyncio.run(main())
99
+ ```
100
+
101
+ `Harness`, `Pipeline`, `Skill`, `SandboxPolicy`, `@tool` and `register_provider` are the public surface. The agent-facing JSON and the optional `tether mcp` server (`tether-sdk[mcp]`) are specified in the [reference](https://igormcsouza.github.io/tether/reference/agent-interface/).
102
+
103
+ ## Contributing
104
+
105
+ Tether stays lightweight, reliable, extensible, model-agnostic, easy to use, resourceful and a token saver; a change that fails one of those lines is reworked. Read [AGENTS.md](AGENTS.md) (the rules and the module map) and [CONTRIBUTING.md](CONTRIBUTING.md) (setup, checks, golden traces, e2e, the bench, releasing). Open an issue before a large change; small fixes with a test and a docs line are welcome as they are.
106
+
107
+ ```text
108
+ tether/ harness · multiplexer · context · store · sandbox · providers/ · tools/
109
+ tests/ unit, golden traces (what the model sees), 100% coverage
110
+ e2e/ real CLI and real Ollama behind a fault-injecting proxy (local)
111
+ bench/ Polyglot-Python and model checks (developers)
112
+ docs/ the user site (MkDocs)
113
+ ```
114
+
115
+ ---
116
+
117
+ ## References
118
+
119
+ 1. **Maia, P. H. M., et al. (2026).** *LLM-Native Applications as a Paradigm for AI-Driven Software Architecture*.
120
+ 2. **Wang, X., Chen, Y., Yuan, L., Zhang, Y., Li, Y., Peng, H., & Ji, H. (2024).** *Executable Code Actions Elicit Better LLM Agents (CodeAct)*. In **Proceedings of the 41st International Conference on Machine Learning (ICML 2024)**. [arXiv:2402.01030](https://arxiv.org/abs/2402.01030)
121
+ 3. **Yang, J., Jimenez, C. E., Wettig, A., Lieret, K., Yao, S., Narasimhan, K., & Press, O. (2024).** *SWE-agent: Agent-Computer Interfaces Enable Automated Software Engineering*. In **Advances in Neural Information Processing Systems (NeurIPS 2024)**. [arXiv:2405.15793](https://arxiv.org/abs/2405.15793)
122
+ 4. **Packer, C., Wooders, S., Lin, K., Fang, V., Patil, S. G., Stoica, I., & Gonzalez, J. E. (2023).** *MemGPT: Towards LLMs as Operating Systems*. [arXiv:2310.08560](https://arxiv.org/abs/2310.08560)
@@ -2,7 +2,7 @@
2
2
 
3
3
  Not part of the `tether` package, not run in CI. Use it to onboard a new model or to check a
4
4
  release for regressions that deterministic tests cannot see (unit, golden and e2e tests stay the
5
- gate; see `docs/testing.md`).
5
+ gate; see `CONTRIBUTING.md`).
6
6
 
7
7
  Nine tasks in `tasks/<name>/` (workspace in `ws/`, goal in `goal.txt`, hidden tests in `hidden/`):
8
8
  `focus` (one exact edit in a distractor-heavy repo, scope-checked), `plan` (an implementation plan, checked for named files, failure handling and tests), `codereview` (eight seeded bugs to find, no edits), `code-simple`, `code-medium`, `code-hard` (graded by hidden unit tests; editing the visible tests
@@ -1,5 +1,7 @@
1
1
  # Architecture and Literature
2
2
 
3
+ *For: people who want to understand why tether works the way it does, and what each design choice costs or saves.*
4
+
3
5
  Most agent frameworks were designed around massive frontier models with 200k-token context windows. When you point those same frameworks at a local 8B or 9B model (`ollama/qwen3.5:9b`, `ollama/gemma4:e4b`), they immediately fail—not because the model cannot reason, but because **3,000 to 8,000 tokens of nested JSON tool schemas and raw tool outputs** flood the attention window before the agent takes its second step.
4
6
 
5
7
  Tether's design translates four foundational works in recent AI systems research into a compact, zero-bloat Python micro-harness.