tsugite-cli 0.9.4__tar.gz → 0.10.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/.gitignore +4 -1
  2. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/PKG-INFO +101 -114
  3. tsugite_cli-0.10.0/README.md +148 -0
  4. tsugite_cli-0.10.0/docs/agents.md +273 -0
  5. tsugite_cli-0.10.0/docs/secrets.md +136 -0
  6. tsugite_cli-0.10.0/docs/test_agents/prefresh_readme.md +16 -0
  7. tsugite_cli-0.10.0/docs/test_agents/template_test.md +14 -0
  8. tsugite_cli-0.10.0/docs/test_agents/test_agent.md +15 -0
  9. tsugite_cli-0.10.0/docs/test_agents/test_steps.md +8 -0
  10. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/pyproject.toml +4 -4
  11. tsugite_cli-0.10.0/scripts/backfill_usage.py +98 -0
  12. tsugite_cli-0.10.0/scripts/update_model_registry.py +189 -0
  13. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/conftest.py +39 -29
  14. tsugite_cli-0.10.0/tests/core/test_agent.py +677 -0
  15. tsugite_cli-0.10.0/tests/core/test_agent_ui_events.py +419 -0
  16. tsugite_cli-0.10.0/tests/core/test_content_blocks.py +269 -0
  17. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_builtin_agent_paths.py +14 -0
  18. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_cache_control.py +1 -4
  19. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_chat_cli.py +23 -5
  20. tsugite_cli-0.10.0/tests/test_claude_code_attachments.py +83 -0
  21. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_claude_code_provider.py +38 -108
  22. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_daemon_compaction_scheduler.py +10 -27
  23. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_daemon_history_persistence.py +1 -1
  24. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_daemon_memory.py +74 -58
  25. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_history.py +25 -0
  26. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_history_models.py +25 -0
  27. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_hooks.py +3 -10
  28. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_kvstore.py +1 -0
  29. tsugite_cli-0.10.0/tests/test_model_registry.py +26 -0
  30. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_models.py +24 -1
  31. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_reasoning_models.py +16 -29
  32. tsugite_cli-0.10.0/tests/test_secrets.py +450 -0
  33. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_session_orchestrator_tools.py +8 -6
  34. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_tmux_tools.py +1 -3
  35. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/__init__.py +0 -4
  36. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/agent_runner/__init__.py +4 -0
  37. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/agent_runner/helpers.py +10 -0
  38. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/agent_runner/history_integration.py +12 -12
  39. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/agent_runner/models.py +1 -3
  40. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/agent_runner/runner.py +29 -15
  41. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/agent_runner/validation.py +1 -0
  42. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/builtin_agents/default.md +19 -0
  43. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/cli/__init__.py +6 -0
  44. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/cli/chat.py +5 -0
  45. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/cli/config.py +0 -1
  46. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/cli/history.py +3 -1
  47. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/cli/init.py +16 -47
  48. tsugite_cli-0.10.0/tsugite/cli/models.py +80 -0
  49. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/cli/run.py +17 -4
  50. tsugite_cli-0.10.0/tsugite/cli/secrets.py +51 -0
  51. tsugite_cli-0.10.0/tsugite/cli/usage.py +134 -0
  52. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/cli/validate.py +1 -1
  53. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/config.py +9 -0
  54. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/core/__init__.py +1 -1
  55. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/core/agent.py +89 -323
  56. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/core/executor.py +9 -5
  57. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/adapters/base.py +52 -31
  58. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/adapters/discord.py +7 -2
  59. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/adapters/http.py +133 -25
  60. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/commands.py +4 -2
  61. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/compaction_scheduler.py +1 -1
  62. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/gateway.py +7 -8
  63. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/memory.py +22 -60
  64. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/session_runner.py +2 -2
  65. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/session_store.py +56 -1
  66. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/web/index.html +129 -7
  67. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/web/js/app.js +3 -1
  68. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/web/js/utils.js +20 -2
  69. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/web/js/views/conversations.js +5 -1
  70. tsugite_cli-0.10.0/tsugite/daemon/web/js/views/usage.js +65 -0
  71. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/history/models.py +4 -3
  72. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/history/storage.py +8 -2
  73. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/kvstore/__init__.py +1 -0
  74. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/md_agents.py +12 -1
  75. tsugite_cli-0.10.0/tsugite/models.py +158 -0
  76. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/plugins.py +3 -1
  77. tsugite_cli-0.10.0/tsugite/providers/__init__.py +97 -0
  78. tsugite_cli-0.10.0/tsugite/providers/anthropic.py +298 -0
  79. tsugite_cli-0.10.0/tsugite/providers/base.py +91 -0
  80. tsugite_cli-0.10.0/tsugite/providers/claude_code.py +255 -0
  81. tsugite_cli-0.10.0/tsugite/providers/model_cache.py +126 -0
  82. tsugite_cli-0.10.0/tsugite/providers/model_registry.py +46 -0
  83. tsugite_cli-0.10.0/tsugite/providers/ollama.py +76 -0
  84. tsugite_cli-0.10.0/tsugite/providers/openai_compat.py +304 -0
  85. tsugite_cli-0.10.0/tsugite/providers/openrouter.py +69 -0
  86. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/schemas/agent.schema.json +16 -2
  87. tsugite_cli-0.10.0/tsugite/secrets/__init__.py +82 -0
  88. tsugite_cli-0.10.0/tsugite/secrets/backend.py +11 -0
  89. tsugite_cli-0.10.0/tsugite/secrets/env.py +25 -0
  90. tsugite_cli-0.10.0/tsugite/secrets/exec.py +75 -0
  91. tsugite_cli-0.10.0/tsugite/secrets/file.py +43 -0
  92. tsugite_cli-0.10.0/tsugite/secrets/masking.py +31 -0
  93. tsugite_cli-0.10.0/tsugite/secrets/registry.py +62 -0
  94. tsugite_cli-0.10.0/tsugite/secrets/sqlite.py +121 -0
  95. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/tools/__init__.py +7 -6
  96. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/tools/kv.py +5 -0
  97. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/tools/schedule.py +1 -0
  98. tsugite_cli-0.10.0/tsugite/tools/secrets.py +48 -0
  99. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/tools/tmux.py +2 -7
  100. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/ui/chat.py +5 -2
  101. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/ui/repl_chat.py +17 -4
  102. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/ui/repl_commands.py +1 -0
  103. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/ui/repl_handler.py +15 -10
  104. tsugite_cli-0.10.0/tsugite/usage/__init__.py +5 -0
  105. tsugite_cli-0.10.0/tsugite/usage/store.py +222 -0
  106. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/utils.py +3 -1
  107. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/uv.lock +5 -340
  108. tsugite_cli-0.9.4/README.md +0 -161
  109. tsugite_cli-0.9.4/tests/core/test_agent.py +0 -782
  110. tsugite_cli-0.9.4/tests/core/test_agent_ui_events.py +0 -434
  111. tsugite_cli-0.9.4/tests/core/test_content_blocks.py +0 -340
  112. tsugite_cli-0.9.4/tests/test_claude_code_attachments.py +0 -245
  113. tsugite_cli-0.9.4/tsugite/models.py +0 -282
  114. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/.github/copilot-instructions.md +0 -0
  115. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/.github/workflows/ci.yml +0 -0
  116. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/.github/workflows/docker-publish.yml +0 -0
  117. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/.github/workflows/pypi-publish.yml +0 -0
  118. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/AGENTS.md +0 -0
  119. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/CLAUDE.md +0 -0
  120. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/LICENSE +0 -0
  121. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/scripts/regenerate_schema.py +0 -0
  122. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/README.md +0 -0
  123. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/__init__.py +0 -0
  124. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/core/__init__.py +0 -0
  125. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/core/test_executor.py +0 -0
  126. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/core/test_memory.py +0 -0
  127. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/core/test_proxy.py +0 -0
  128. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/core/test_sandbox.py +0 -0
  129. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/core/test_subprocess_executor.py +0 -0
  130. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/core/test_tools.py +0 -0
  131. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/daemon/__init__.py +0 -0
  132. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/daemon/test_http_adapter.py +0 -0
  133. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/events/test_event_consolidation.py +0 -0
  134. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/smoke_test.sh +0 -0
  135. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_agent_file_hot_loading.py +0 -0
  136. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_agent_inheritance.py +0 -0
  137. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_agent_parser.py +0 -0
  138. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_agent_sessions.py +0 -0
  139. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_agent_skills.py +0 -0
  140. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_agent_utils.py +0 -0
  141. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_agents_tool.py +0 -0
  142. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_attachment_deduplication.py +0 -0
  143. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_attachments.py +0 -0
  144. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_auto_context_handler.py +0 -0
  145. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_auto_discovery.py +0 -0
  146. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_background_task_status.py +0 -0
  147. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_background_tasks.py +0 -0
  148. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_builtin_agents.py +0 -0
  149. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_chat_error_handling.py +0 -0
  150. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_cli.py +0 -0
  151. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_cli_arguments.py +0 -0
  152. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_cli_rendering.py +0 -0
  153. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_cli_subcommands.py +0 -0
  154. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_config.py +0 -0
  155. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_continuation.py +0 -0
  156. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_custom_shell_tools.py +0 -0
  157. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_custom_ui.py +0 -0
  158. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_daemon_config.py +0 -0
  159. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_daemon_push.py +0 -0
  160. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_daemon_scheduler.py +0 -0
  161. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_daemon_session_isolation.py +0 -0
  162. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_daemon_unified_sessions.py +0 -0
  163. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_discord_progress.py +0 -0
  164. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_error_display.py +0 -0
  165. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_file_references.py +0 -0
  166. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_file_tools.py +0 -0
  167. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_history_integration.py +0 -0
  168. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_history_performance.py +0 -0
  169. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_history_tools.py +0 -0
  170. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_http_tools.py +0 -0
  171. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_interaction_backends.py +0 -0
  172. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_interactive_context.py +0 -0
  173. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_interactive_tool.py +0 -0
  174. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_jsonl_ui.py +0 -0
  175. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_list_agents_tool.py +0 -0
  176. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_mcp_client.py +0 -0
  177. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_mcp_server.py +0 -0
  178. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_multi_agent.py +0 -0
  179. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_multistep_agents.py +0 -0
  180. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_orchestrator_heartbeat.py +0 -0
  181. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_plugins.py +0 -0
  182. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_renderer.py +0 -0
  183. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_rendering_scenarios.py +0 -0
  184. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_repl_commands.py +0 -0
  185. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_repl_completer.py +0 -0
  186. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_repl_handler.py +0 -0
  187. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_retry_system.py +0 -0
  188. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_run_if.py +0 -0
  189. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_schedule_model_override.py +0 -0
  190. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_scheduler_history_injection.py +0 -0
  191. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_schema.py +0 -0
  192. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_security_phase1.py +0 -0
  193. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_send_message.py +0 -0
  194. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_skill_discovery.py +0 -0
  195. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_skill_tools.py +0 -0
  196. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_stdin.py +0 -0
  197. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_subagent_subprocess.py +0 -0
  198. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_tool_directives.py +0 -0
  199. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_tool_registry.py +0 -0
  200. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_workspace_auto_continue.py +0 -0
  201. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_workspace_cwd.py +0 -0
  202. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tests/test_workspace_discovery.py +0 -0
  203. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/agent_inheritance.py +0 -0
  204. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/agent_preparation.py +0 -0
  205. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/agent_runner/metrics.py +0 -0
  206. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/agent_utils.py +0 -0
  207. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/attachments/__init__.py +0 -0
  208. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/attachments/auto_context.py +0 -0
  209. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/attachments/base.py +0 -0
  210. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/attachments/file.py +0 -0
  211. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/attachments/inline.py +0 -0
  212. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/attachments/storage.py +0 -0
  213. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/attachments/url.py +0 -0
  214. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/attachments/youtube.py +0 -0
  215. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/builtin_agents/.gitkeep +0 -0
  216. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/builtin_agents/code_searcher.md +0 -0
  217. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/builtin_agents/file_searcher.md +0 -0
  218. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/builtin_agents/onboard.md +0 -0
  219. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/builtin_skills/.gitkeep +0 -0
  220. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/builtin_skills/codebase_exploration.md +0 -0
  221. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/builtin_skills/python_math.md +0 -0
  222. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/builtin_skills/response_patterns.md +0 -0
  223. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/builtin_skills/scheduling.md +0 -0
  224. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/builtin_skills/skill_authoring.md +0 -0
  225. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/builtin_skills/tsugite_agent_basics.md +0 -0
  226. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/builtin_skills/tsugite_jinja_reference.md +0 -0
  227. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/builtin_skills/tsugite_skill_basics.md +0 -0
  228. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/cache.py +0 -0
  229. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/cli/agents.py +0 -0
  230. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/cli/attachments.py +0 -0
  231. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/cli/cache.py +0 -0
  232. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/cli/daemon.py +0 -0
  233. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/cli/helpers.py +0 -0
  234. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/cli/mcp.py +0 -0
  235. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/cli/plugins.py +0 -0
  236. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/cli/render.py +0 -0
  237. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/cli/serve.py +0 -0
  238. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/cli/tools.py +0 -0
  239. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/cli/workspace.py +0 -0
  240. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/console.py +0 -0
  241. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/constants.py +0 -0
  242. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/core/claude_code.py +0 -0
  243. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/core/content_blocks.py +0 -0
  244. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/core/memory.py +0 -0
  245. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/core/proxy.py +0 -0
  246. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/core/sandbox.py +0 -0
  247. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/core/subprocess_executor.py +0 -0
  248. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/core/tools.py +0 -0
  249. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/__init__.py +0 -0
  250. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/adapters/__init__.py +0 -0
  251. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/adapters/scheduler_adapter.py +0 -0
  252. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/config.py +0 -0
  253. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/push.py +0 -0
  254. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/scheduler.py +0 -0
  255. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/web/css/responsive.css +0 -0
  256. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/web/css/styles.css +0 -0
  257. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/web/css/theme.css +0 -0
  258. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/web/icons/icon-192.png +0 -0
  259. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/web/icons/icon-512-maskable.png +0 -0
  260. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/web/icons/icon-512.png +0 -0
  261. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/web/icons/screenshot-narrow.png +0 -0
  262. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/web/icons/screenshot-wide.png +0 -0
  263. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/web/js/api.js +0 -0
  264. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/web/js/views/dashboard.js +0 -0
  265. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/web/js/views/file-editor.js +0 -0
  266. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/web/js/views/kvstore.js +0 -0
  267. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/web/js/views/schedules.js +0 -0
  268. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/web/js/views/webhooks.js +0 -0
  269. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/web/js/views/workspace.js +0 -0
  270. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/web/manifest.json +0 -0
  271. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/web/sw.js +0 -0
  272. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/daemon/webhook_store.py +0 -0
  273. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/events/__init__.py +0 -0
  274. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/events/base.py +0 -0
  275. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/events/bus.py +0 -0
  276. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/events/events.py +0 -0
  277. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/events/helpers.py +0 -0
  278. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/exceptions.py +0 -0
  279. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/history/__init__.py +0 -0
  280. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/history/reconstruction.py +0 -0
  281. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/hooks.py +0 -0
  282. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/interaction.py +0 -0
  283. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/kvstore/backend.py +0 -0
  284. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/kvstore/sqlite.py +0 -0
  285. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/mcp_client.py +0 -0
  286. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/mcp_config.py +0 -0
  287. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/mcp_server.py +0 -0
  288. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/options.py +0 -0
  289. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/renderer.py +0 -0
  290. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/schemas/__init__.py +0 -0
  291. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/shell_tool_config.py +0 -0
  292. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/skill_discovery.py +0 -0
  293. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/templates/AGENTS.md +0 -0
  294. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/templates/IDENTITY.md +0 -0
  295. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/templates/MEMORY.md +0 -0
  296. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/templates/USER.md +0 -0
  297. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/templates/personas/casual-technical.md +0 -0
  298. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/templates/personas/marvin.md +0 -0
  299. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/templates/personas/minimal.md +0 -0
  300. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/tools/agents.py +0 -0
  301. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/tools/fs.py +0 -0
  302. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/tools/history.py +0 -0
  303. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/tools/http.py +0 -0
  304. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/tools/interactive.py +0 -0
  305. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/tools/notify.py +0 -0
  306. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/tools/sessions.py +0 -0
  307. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/tools/shell.py +0 -0
  308. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/tools/shell_tools.py +0 -0
  309. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/tools/skills.py +0 -0
  310. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/tsugite.py +0 -0
  311. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/ui/__init__.py +0 -0
  312. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/ui/base.py +0 -0
  313. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/ui/helpers.py +0 -0
  314. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/ui/jsonl.py +0 -0
  315. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/ui/plain.py +0 -0
  316. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/ui/repl_completer.py +0 -0
  317. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/ui_context.py +0 -0
  318. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/workspace/__init__.py +0 -0
  319. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/workspace/context.py +0 -0
  320. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/workspace/models.py +0 -0
  321. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/workspace/session.py +0 -0
  322. {tsugite_cli-0.9.4 → tsugite_cli-0.10.0}/tsugite/workspace/templates.py +0 -0
@@ -167,13 +167,16 @@ cython_debug/
167
167
  benchmark_results/
168
168
  test_output/
169
169
  .claude/settings.local.json
170
+ std*.txt
171
+ secrets/*
170
172
 
171
173
 
172
174
  # TODO: temp - I need to clean up the docs
173
- docs/
175
+ docs-old/
174
176
  examples/
175
177
  agents/
176
178
  .claude/
177
179
  .tsugite/
178
180
  benchmarks/
181
+ docker-compose.test.yml
179
182
  #### TODO ^^^
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tsugite-cli
3
- Version: 0.9.4
3
+ Version: 0.10.0
4
4
  Summary: Micro-agent runner for task automation using markdown definitions
5
5
  Author: Justyn Shull
6
6
  License: GNU AFFERO GENERAL PUBLIC LICENSE
@@ -239,15 +239,14 @@ License: GNU AFFERO GENERAL PUBLIC LICENSE
239
239
 
240
240
  You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see <http://www.gnu.org/licenses/>.
241
241
  License-File: LICENSE
242
- Keywords: agents,automation,cli,jinja2,litellm
242
+ Keywords: agents,automation,cli,jinja2
243
243
  Requires-Python: >=3.11
244
+ Requires-Dist: cryptography>=46.0.5
244
245
  Requires-Dist: ddgs>=9.6.0
245
246
  Requires-Dist: html2text>=2020.1.16
246
247
  Requires-Dist: httpx>=0.25
247
248
  Requires-Dist: jinja2>=3.1
248
- Requires-Dist: litellm<1.82.7,>=1.77.7
249
249
  Requires-Dist: mcp>=1.0
250
- Requires-Dist: nest-asyncio>=1.6.0
251
250
  Requires-Dist: pathspec>=0.11.0
252
251
  Requires-Dist: portalocker>=2.8.0
253
252
  Requires-Dist: prompt-toolkit>=3.0.43
@@ -255,6 +254,7 @@ Requires-Dist: pydantic>=2.12.3
255
254
  Requires-Dist: pyyaml>=6.0
256
255
  Requires-Dist: questionary>=2.1.1
257
256
  Requires-Dist: rich>=13.0
257
+ Requires-Dist: tiktoken>=0.7.0
258
258
  Requires-Dist: typer>=0.12
259
259
  Requires-Dist: tzlocal>=5.3.1
260
260
  Requires-Dist: youtube-transcript-api>=0.6.0
@@ -269,162 +269,149 @@ Description-Content-Type: text/markdown
269
269
 
270
270
  # tsugite
271
271
 
272
- Tsugite (Japanese: 継ぎ手, the art of joinery in woodworking) is a developer-facing agentic CLI.
272
+ Tsugite (継ぎ手) is an agent framework where you define AI agents as markdown files and run them from the CLI, a web UI, or through scheduled tasks.
273
273
 
274
- Define AI agents as markdown files with YAML frontmatter. Chain multiple steps together, pass data between them, and use any LLM (OpenAI, Anthropic, Ollama, etc).
274
+ I built it because none of the existing agent frameworks did what I wanted. I needed something self-hosted, model-agnostic, and simple enough that an agent is just a text file I can edit and version control.
275
275
 
276
- ## Installation
276
+ Originally it was meant to be a framework for micro-agents inspired by [ESA](https://github.com/meain/esa), but has grown a lot since that goal.
277
277
 
278
- ```bash
279
- # Recommended: Install with uv
280
- uv tool install tsugite-cli
281
-
282
- # Alternative: Install with pipx
283
- pipx install tsugite-cli
284
-
285
- # Or with pip
286
- pip install tsugite-cli
287
- ```
288
-
289
- **Note:** The package name is `tsugite-cli`, but the command is `tsugite` (or `tsu` for short).
278
+ ## What an agent looks like
290
279
 
291
- ## Quick Start
280
+ A simple "hello world" agent looks like:
292
281
 
293
- ```bash
294
- # Run an agent
295
- tsugite run examples/simple_variable_injection.md "test it"
296
-
297
- # Create your own agent
298
- cat > my_agent.md << 'EOF'
282
+ ```markdown
299
283
  ---
300
- name: hello
301
- model: openai:gpt-4o-mini
284
+ name: morning-brief
285
+ model: anthropic:claude-sonnet-4-20250514
286
+ tools: [web_search, fetch_text, write_file, final_answer]
302
287
  ---
303
288
 
304
- Task: {{ user_prompt }}
289
+ You are a morning briefing assistant.
305
290
 
306
- Just say hello and use final_answer() to return your greeting.
307
- EOF
291
+ Current date: {{ now() }}
292
+ User location: {{ env("LOCATION", "unknown") }}
308
293
 
309
- tsugite run my_agent.md "greet the user"
294
+ Check the weather, scan top news, and write a short briefing.
295
+ Use final_answer() to return the result.
310
296
  ```
311
297
 
312
- ## Features
298
+ YAML frontmatter for config, markdown body for instructions, Jinja for dynamic context. Run it with:
313
299
 
314
- - **Multi-step workflows** - Chain steps with `<!-- tsu:step -->`, pass data between them
315
- - **Variable injection** - Step outputs automatically available as Python variables
316
- - **Multiple LLM providers** - OpenAI, Anthropic, Ollama, Google, GitHub Copilot
317
- - **MCP integration** - Connect to Model Context Protocol servers
318
- - **Temperature control** - Set per-step model parameters
319
- - **Copy-paste friendly output** - `--plain` flag or auto-detection for pipe/redirect
300
+ ```bash
301
+ tsu run +morning-brief "what's happening today"
302
+ ```
303
+
304
+ ## Key ideas
320
305
 
321
- ## CLI Options
306
+ - **Agents are markdown.** A basic agent is just markdown with yaml frontmatter. Advanced agents are still just markdown but can use jinja templating and a special `<!--tsu -->` syntax.
307
+ - **Code execution over tool-calling.** Inspired by [smolagents](https://github.com/huggingface/smolagents). Instead of using native tool calling, LLMs write python code. Tools are exposed as python functions.
308
+ - **Any LLM.** Plugin interface to add support for additional LLM providers. Built-in we have openai-compatible apis, ollama, anthropic, and claude code.
309
+ - **Workspaces.** Each workspace is a persistent directory with agents, skills, memory files, and config. The agent runs inside its workspace and can read/write files, spawn sub-agents, manage schedules, and persist state across conversations. Workspaces are entirely optional.
310
+ - **CLI and/or Daemon with a Web UI** Use `tsu run` commands for cli-only, or run `tsu daemon` for a daemon that supports scheduled tasks, a web ui, and some other neat things.
311
+
312
+ ## Install
322
313
 
323
314
  ```bash
324
- # Plain output (no box-drawing characters, copy-paste friendly)
325
- tsugite run +assistant "task" --plain
315
+ uv tool install tsugite-cli # recommended
316
+ pipx install tsugite-cli # alternative
317
+ pip install tsugite-cli # or plain pip
318
+ ```
326
319
 
327
- # Auto-detection: plain mode activates when piped or NO_COLOR is set
328
- tsugite run +assistant "task" | grep result
320
+ The package is `tsugite-cli`, the command is `tsugite` (or `tsu` for short).
329
321
 
330
- # Headless mode for scripts (result to stdout, progress to stderr)
331
- tsugite run +assistant "task" --headless
322
+ ## Quick start
332
323
 
333
- # Continue latest conversation (auto-detects agent)
334
- tsugite run --continue "follow-up prompt"
324
+ ```bash
325
+ # Initialize a workspace
326
+ tsu init my-workspace
327
+ cd my-workspace
328
+
329
+ # Run the built-in default agent
330
+ tsu run +default "summarize the files in this directory"
335
331
 
336
- # Continue specific conversation
337
- tsugite run --continue --conversation-id CONV_ID "follow-up prompt"
338
- tsugite chat --continue CONV_ID
332
+ # Run an agent file directly
333
+ tsu run my-agent.md "do the thing"
339
334
 
340
- # View conversation history
341
- tsugite history list
342
- tsugite history show CONV_ID
335
+ # Start the web UI
336
+ tsu serve
343
337
  ```
344
338
 
345
- ## Sandbox
339
+ ## Features
346
340
 
347
- Agent code can run inside a [bubblewrap](https://github.com/containers/bubblewrap) sandbox with filesystem and network isolation.
341
+ - **Multi-step workflows** with `<!-- tsu:step -->` to chain steps and pass data between them
342
+ - **Scheduling** built-in cron for recurring agent tasks (daily summaries, monitoring, etc.)
343
+ - **Web UI** for conversations, with Discord as an alternative interface
344
+ - **Sub-agents** that can spawn other agents for specific subtasks
345
+ - **Skills** reusable knowledge files agents can load on demand, mostly compatible with [agentskills.io](https://agentskills.io/)
346
+ - **Hooks** that fire shell commands on lifecycle events (post-tool, pre-message, pre/post-compact)
347
+ - **Sandbox** (linux only) via bubblewrap with filesystem and network isolation
348
+ - **KV store** for persistent agent state
349
+ - **MCP** integration for connecting to MCP servers
348
350
 
349
- ```bash
350
- # Sandbox with specific domains allowed
351
- tsu run +default "task" --sandbox --allow-domain "github.com" --allow-domain "*.openai.com"
351
+ ## Agents in more detail
352
352
 
353
- # Full network isolation
354
- tsu run +default "task" --sandbox --no-network
353
+ Agents support YAML frontmatter for configuration:
354
+
355
+ ```yaml
356
+ ---
357
+ name: code-reviewer
358
+ model: anthropic:claude-sonnet-4-20250514
359
+ max_turns: 15
360
+ tools: [read_file, list_files, web_search, final_answer]
361
+ auto_load_skills: [coding-standards]
362
+ ---
355
363
  ```
356
364
 
357
- **How it works:**
365
+ You can restrict which tools an agent has access to, set turn limits, auto-load skills, attach context files, and extend other agents. TODO: See `docs/` for the full spec.
358
366
 
359
- ```
360
- CLI --sandbox --allow-domain "*.github.com"
361
- └─ SubprocessExecutor writes harness script
362
- └─ bwrap --unshare-pid --unshare-net --die-with-parent ...
363
- └─ TCP↔UDS bridge (HTTP_PROXY → Unix socket)
364
- └─ ConnectProxy filters CONNECT requests by domain:port
365
- ```
367
+ Multi-step agents use `<!--tsu -->` comments as directives:
366
368
 
367
- **Default mounts:**
369
+ ```markdown
370
+ <!-- tsu:step name="research" model="openai:gpt-4o" -->
371
+ Research the topic and save findings to a variable.
368
372
 
369
- - Read-only: `/usr`, `/lib`, `/lib64`, `/bin`, `/sbin`, `/etc/ssl`, `/etc/resolv.conf`, CA certs, Python venv + `sys.path`
370
- - Read-write: workspace directory, internal state directory
371
- - Tmpfs: `/tmp` (fresh each run)
373
+ <!-- tsu:step name="write" -->
374
+ Using the research from the previous step, write a summary.
375
+ The variable `research` is available as a Python variable.
376
+ ```
372
377
 
373
- Extra bind mounts can be added programmatically via `SandboxConfig.extra_ro_binds` and `extra_rw_binds`, but these are not yet exposed through CLI flags or agent frontmatter.
378
+ For a complete example, check the built-in [default agent](tsugite/builtin_agents/default.md).
374
379
 
375
- **Network:**
376
- - Network is namespace-isolated; outbound HTTP/HTTPS goes through a filtering CONNECT proxy
377
- - Direct connections to bare IP addresses are always blocked
378
- - `--no-network` skips the proxy entirely — no connectivity at all
380
+ ## Sandbox
379
381
 
380
- **`--allow-domain` syntax:**
382
+ On Linux only (for now), agent code runs inside a [bubblewrap](https://github.com/containers/bubblewrap) sandbox when you pass `--sandbox`:
381
383
 
382
- | Pattern | Allows |
383
- |---|---|
384
- | `github.com` | ports 80, 443 |
385
- | `github.com:22` | port 22 only |
386
- | `*.github.com:8080` | port 8080 on subdomains |
387
- | `*:*` | all domains, all ports |
384
+ ```bash
385
+ tsu run +default "task" --sandbox --allow-domain "github.com"
386
+ tsu run +default "task" --sandbox --no-network
387
+ ```
388
388
 
389
- ## Hooks
389
+ Filesystem access is limited to the workspace. Network goes through a filtering proxy that only allows domains you specify.
390
390
 
391
- Hooks fire shell commands at lifecycle points. Configure in `.tsugite/hooks.yaml`:
391
+ ## Config and Data Directories
392
392
 
393
- ```yaml
394
- hooks:
395
- post_tool:
396
- - tools: [write_file]
397
- run: git add {{ path }}
398
- wait: true
399
-
400
- pre_message:
401
- - run: uridx search "{{ message }}" --limit 5
402
- capture_as: rag_context
403
- - run: cat memory/preferences.md
404
- capture_as: user_preferences
405
-
406
- pre_compact:
407
- - run: ./scripts/extract-facts.sh {{ turns_file }}
408
- wait: true
409
-
410
- post_compact:
411
- - run: echo "Compacted {{ turns_compacted }} turns"
412
- ```
393
+ All paths follow [XDG Base Directory](https://specifications.freedesktop.org/basedir-spec/latest/) conventions and can be overridden with the standard environment variables.
413
394
 
414
- **Hook fields:** `run` (Jinja2 shell command), `tools` (tool filter, `post_tool` only), `match` (Jinja2 condition), `wait` (block until done), `capture_as` (capture stdout into a template variable, implies `wait`).
395
+ | Path | Default | Contents |
396
+ |----------------------------------------|--------------------------------------|----------------------------------------------|
397
+ | `$XDG_CONFIG_HOME/tsugite/` | `~/.config/tsugite/` | `config.json`, `mcp.json`, `daemon.yaml` |
398
+ | `$XDG_DATA_HOME/tsugite/history/` | `~/.local/share/tsugite/history/` | Session history (JSONL per session) |
399
+ | `$XDG_DATA_HOME/tsugite/daemon/` | `~/.local/share/tsugite/daemon/` | Daemon state |
400
+ | `$XDG_DATA_HOME/tsugite/secrets/` | `~/.local/share/tsugite/secrets/` | Encrypted secrets (`secrets.db`) |
401
+ | `$XDG_DATA_HOME/tsugite/kvstore/` | `~/.local/share/tsugite/kvstore/` | Key-value store (`kv.db`) |
402
+ | `$XDG_DATA_HOME/tsugite/usage/` | `~/.local/share/tsugite/usage/` | Usage (cost and token) tracking (`usage.db`) |
403
+ | `$XDG_DATA_HOME/tsugite/workspaces/` | `~/.local/share/tsugite/workspaces/` | Workspace directories |
404
+ | `$XDG_CACHE_HOME/tsugite/attachments/` | `~/.cache/tsugite/attachments/` | Attachment cache |
415
405
 
416
- **Hook types:**
417
- - **`post_tool`** — After successful tool calls. Context: `tool`, plus tool arguments.
418
- - **`pre_message`** — Before agent execution. Context: `message`, `user_id`, `agent_name`. Use `capture_as` to inject results into agent templates as `{{ var_name }}`.
419
- - **`pre_compact`** / **`post_compact`** — Around session compaction. Context: `conversation_id`, `user_id`, `agent_name`, `turns_file`, `turn_count`.
420
406
 
421
407
  ## Development
422
408
 
423
409
  ```bash
424
- # Clone and install for development
425
410
  git clone https://github.com/justyns/tsugite.git
426
411
  cd tsugite
427
412
  uv sync --dev
428
413
  ```
429
414
 
430
- See `examples/` for working agents and `CLAUDE.md` for AI-generated documentation.
415
+ ## Status
416
+
417
+ This is a personal project I use daily. It works for my use cases but isn't polished for general consumption yet. Issues and PRs welcome, but set expectations accordingly. Documentation is very sparse because I keep changing things.
@@ -0,0 +1,148 @@
1
+ # tsugite
2
+
3
+ Tsugite (継ぎ手) is an agent framework where you define AI agents as markdown files and run them from the CLI, a web UI, or through scheduled tasks.
4
+
5
+ I built it because none of the existing agent frameworks did what I wanted. I needed something self-hosted, model-agnostic, and simple enough that an agent is just a text file I can edit and version control.
6
+
7
+ Originally it was meant to be a framework for micro-agents inspired by [ESA](https://github.com/meain/esa), but has grown a lot since that goal.
8
+
9
+ ## What an agent looks like
10
+
11
+ A simple "hello world" agent looks like:
12
+
13
+ ```markdown
14
+ ---
15
+ name: morning-brief
16
+ model: anthropic:claude-sonnet-4-20250514
17
+ tools: [web_search, fetch_text, write_file, final_answer]
18
+ ---
19
+
20
+ You are a morning briefing assistant.
21
+
22
+ Current date: {{ now() }}
23
+ User location: {{ env("LOCATION", "unknown") }}
24
+
25
+ Check the weather, scan top news, and write a short briefing.
26
+ Use final_answer() to return the result.
27
+ ```
28
+
29
+ YAML frontmatter for config, markdown body for instructions, Jinja for dynamic context. Run it with:
30
+
31
+ ```bash
32
+ tsu run +morning-brief "what's happening today"
33
+ ```
34
+
35
+ ## Key ideas
36
+
37
+ - **Agents are markdown.** A basic agent is just markdown with yaml frontmatter. Advanced agents are still just markdown but can use jinja templating and a special `<!--tsu -->` syntax.
38
+ - **Code execution over tool-calling.** Inspired by [smolagents](https://github.com/huggingface/smolagents). Instead of using native tool calling, LLMs write python code. Tools are exposed as python functions.
39
+ - **Any LLM.** Plugin interface to add support for additional LLM providers. Built-in we have openai-compatible apis, ollama, anthropic, and claude code.
40
+ - **Workspaces.** Each workspace is a persistent directory with agents, skills, memory files, and config. The agent runs inside its workspace and can read/write files, spawn sub-agents, manage schedules, and persist state across conversations. Workspaces are entirely optional.
41
+ - **CLI and/or Daemon with a Web UI** Use `tsu run` commands for cli-only, or run `tsu daemon` for a daemon that supports scheduled tasks, a web ui, and some other neat things.
42
+
43
+ ## Install
44
+
45
+ ```bash
46
+ uv tool install tsugite-cli # recommended
47
+ pipx install tsugite-cli # alternative
48
+ pip install tsugite-cli # or plain pip
49
+ ```
50
+
51
+ The package is `tsugite-cli`, the command is `tsugite` (or `tsu` for short).
52
+
53
+ ## Quick start
54
+
55
+ ```bash
56
+ # Initialize a workspace
57
+ tsu init my-workspace
58
+ cd my-workspace
59
+
60
+ # Run the built-in default agent
61
+ tsu run +default "summarize the files in this directory"
62
+
63
+ # Run an agent file directly
64
+ tsu run my-agent.md "do the thing"
65
+
66
+ # Start the web UI
67
+ tsu serve
68
+ ```
69
+
70
+ ## Features
71
+
72
+ - **Multi-step workflows** with `<!-- tsu:step -->` to chain steps and pass data between them
73
+ - **Scheduling** built-in cron for recurring agent tasks (daily summaries, monitoring, etc.)
74
+ - **Web UI** for conversations, with Discord as an alternative interface
75
+ - **Sub-agents** that can spawn other agents for specific subtasks
76
+ - **Skills** reusable knowledge files agents can load on demand, mostly compatible with [agentskills.io](https://agentskills.io/)
77
+ - **Hooks** that fire shell commands on lifecycle events (post-tool, pre-message, pre/post-compact)
78
+ - **Sandbox** (linux only) via bubblewrap with filesystem and network isolation
79
+ - **KV store** for persistent agent state
80
+ - **MCP** integration for connecting to MCP servers
81
+
82
+ ## Agents in more detail
83
+
84
+ Agents support YAML frontmatter for configuration:
85
+
86
+ ```yaml
87
+ ---
88
+ name: code-reviewer
89
+ model: anthropic:claude-sonnet-4-20250514
90
+ max_turns: 15
91
+ tools: [read_file, list_files, web_search, final_answer]
92
+ auto_load_skills: [coding-standards]
93
+ ---
94
+ ```
95
+
96
+ You can restrict which tools an agent has access to, set turn limits, auto-load skills, attach context files, and extend other agents. TODO: See `docs/` for the full spec.
97
+
98
+ Multi-step agents use `<!--tsu -->` comments as directives:
99
+
100
+ ```markdown
101
+ <!-- tsu:step name="research" model="openai:gpt-4o" -->
102
+ Research the topic and save findings to a variable.
103
+
104
+ <!-- tsu:step name="write" -->
105
+ Using the research from the previous step, write a summary.
106
+ The variable `research` is available as a Python variable.
107
+ ```
108
+
109
+ For a complete example, check the built-in [default agent](tsugite/builtin_agents/default.md).
110
+
111
+ ## Sandbox
112
+
113
+ On Linux only (for now), agent code runs inside a [bubblewrap](https://github.com/containers/bubblewrap) sandbox when you pass `--sandbox`:
114
+
115
+ ```bash
116
+ tsu run +default "task" --sandbox --allow-domain "github.com"
117
+ tsu run +default "task" --sandbox --no-network
118
+ ```
119
+
120
+ Filesystem access is limited to the workspace. Network goes through a filtering proxy that only allows domains you specify.
121
+
122
+ ## Config and Data Directories
123
+
124
+ All paths follow [XDG Base Directory](https://specifications.freedesktop.org/basedir-spec/latest/) conventions and can be overridden with the standard environment variables.
125
+
126
+ | Path | Default | Contents |
127
+ |----------------------------------------|--------------------------------------|----------------------------------------------|
128
+ | `$XDG_CONFIG_HOME/tsugite/` | `~/.config/tsugite/` | `config.json`, `mcp.json`, `daemon.yaml` |
129
+ | `$XDG_DATA_HOME/tsugite/history/` | `~/.local/share/tsugite/history/` | Session history (JSONL per session) |
130
+ | `$XDG_DATA_HOME/tsugite/daemon/` | `~/.local/share/tsugite/daemon/` | Daemon state |
131
+ | `$XDG_DATA_HOME/tsugite/secrets/` | `~/.local/share/tsugite/secrets/` | Encrypted secrets (`secrets.db`) |
132
+ | `$XDG_DATA_HOME/tsugite/kvstore/` | `~/.local/share/tsugite/kvstore/` | Key-value store (`kv.db`) |
133
+ | `$XDG_DATA_HOME/tsugite/usage/` | `~/.local/share/tsugite/usage/` | Usage (cost and token) tracking (`usage.db`) |
134
+ | `$XDG_DATA_HOME/tsugite/workspaces/` | `~/.local/share/tsugite/workspaces/` | Workspace directories |
135
+ | `$XDG_CACHE_HOME/tsugite/attachments/` | `~/.cache/tsugite/attachments/` | Attachment cache |
136
+
137
+
138
+ ## Development
139
+
140
+ ```bash
141
+ git clone https://github.com/justyns/tsugite.git
142
+ cd tsugite
143
+ uv sync --dev
144
+ ```
145
+
146
+ ## Status
147
+
148
+ This is a personal project I use daily. It works for my use cases but isn't polished for general consumption yet. Issues and PRs welcome, but set expectations accordingly. Documentation is very sparse because I keep changing things.