tsugite-cli 0.3.3__tar.gz → 0.8.2__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.
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/.github/copilot-instructions.md +8 -12
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/.gitignore +11 -1
- tsugite_cli-0.8.2/AGENTS.md +354 -0
- tsugite_cli-0.8.2/CLAUDE.md +1 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/PKG-INFO +112 -7
- tsugite_cli-0.8.2/README.md +161 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/pyproject.toml +20 -7
- tsugite_cli-0.8.2/scripts/regenerate_schema.py +33 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/conftest.py +162 -37
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/core/test_agent.py +175 -122
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/core/test_agent_ui_events.py +70 -142
- tsugite_cli-0.8.2/tests/core/test_content_blocks.py +340 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/core/test_executor.py +248 -1
- tsugite_cli-0.8.2/tests/core/test_proxy.py +165 -0
- tsugite_cli-0.8.2/tests/core/test_sandbox.py +171 -0
- tsugite_cli-0.8.2/tests/core/test_subprocess_executor.py +353 -0
- tsugite_cli-0.8.2/tests/daemon/__init__.py +0 -0
- tsugite_cli-0.8.2/tests/daemon/test_http_adapter.py +252 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/events/test_event_consolidation.py +27 -62
- tsugite_cli-0.8.2/tests/test_agent_file_hot_loading.py +279 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_agent_inheritance.py +22 -138
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_agent_parser.py +8 -179
- tsugite_cli-0.8.2/tests/test_agent_sessions.py +312 -0
- tsugite_cli-0.8.2/tests/test_agent_skills.py +610 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_agent_utils.py +27 -53
- tsugite_cli-0.8.2/tests/test_attachment_deduplication.py +281 -0
- tsugite_cli-0.8.2/tests/test_attachments.py +448 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_auto_context_handler.py +44 -46
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_auto_discovery.py +10 -18
- tsugite_cli-0.8.2/tests/test_background_task_status.py +187 -0
- tsugite_cli-0.8.2/tests/test_background_tasks.py +529 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_builtin_agent_paths.py +5 -9
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_builtin_agents.py +22 -89
- tsugite_cli-0.8.2/tests/test_cache_control.py +184 -0
- tsugite_cli-0.8.2/tests/test_chat_error_handling.py +65 -0
- tsugite_cli-0.8.2/tests/test_claude_code_attachments.py +245 -0
- tsugite_cli-0.8.2/tests/test_claude_code_provider.py +609 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_cli.py +102 -31
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_cli_rendering.py +51 -28
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_cli_subcommands.py +3 -19
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_config.py +29 -13
- tsugite_cli-0.8.2/tests/test_continuation.py +453 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_custom_ui.py +0 -37
- tsugite_cli-0.8.2/tests/test_daemon_compaction_scheduler.py +208 -0
- tsugite_cli-0.8.2/tests/test_daemon_config.py +133 -0
- tsugite_cli-0.8.2/tests/test_daemon_history_persistence.py +514 -0
- tsugite_cli-0.8.2/tests/test_daemon_memory.py +465 -0
- tsugite_cli-0.8.2/tests/test_daemon_push.py +260 -0
- tsugite_cli-0.8.2/tests/test_daemon_scheduler.py +625 -0
- tsugite_cli-0.8.2/tests/test_daemon_session_isolation.py +265 -0
- tsugite_cli-0.8.2/tests/test_daemon_unified_sessions.py +350 -0
- tsugite_cli-0.8.2/tests/test_discord_progress.py +302 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_file_references.py +65 -48
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_file_tools.py +216 -44
- tsugite_cli-0.8.2/tests/test_history.py +389 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_history_integration.py +140 -96
- tsugite_cli-0.8.2/tests/test_history_models.py +492 -0
- tsugite_cli-0.8.2/tests/test_history_performance.py +202 -0
- tsugite_cli-0.8.2/tests/test_history_tools.py +267 -0
- tsugite_cli-0.8.2/tests/test_hooks.py +951 -0
- tsugite_cli-0.8.2/tests/test_http_tools.py +223 -0
- tsugite_cli-0.8.2/tests/test_interaction_backends.py +246 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_interactive_context.py +98 -61
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_jsonl_ui.py +2 -21
- tsugite_cli-0.8.2/tests/test_kvstore.py +120 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_list_agents_tool.py +23 -43
- tsugite_cli-0.8.2/tests/test_mcp_server.py +109 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_models.py +3 -3
- tsugite_cli-0.8.2/tests/test_multi_agent.py +162 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_multistep_agents.py +58 -383
- tsugite_cli-0.8.2/tests/test_orchestrator_heartbeat.py +228 -0
- tsugite_cli-0.8.2/tests/test_plugins.py +174 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_rendering_scenarios.py +3 -3
- tsugite_cli-0.8.2/tests/test_repl_commands.py +274 -0
- tsugite_cli-0.8.2/tests/test_repl_completer.py +105 -0
- tsugite_cli-0.8.2/tests/test_repl_handler.py +187 -0
- tsugite_cli-0.8.2/tests/test_run_if.py +92 -0
- tsugite_cli-0.8.2/tests/test_schedule_model_override.py +109 -0
- tsugite_cli-0.8.2/tests/test_scheduler_history_injection.py +172 -0
- tsugite_cli-0.8.2/tests/test_schema.py +206 -0
- tsugite_cli-0.8.2/tests/test_security_phase1.py +319 -0
- tsugite_cli-0.8.2/tests/test_send_message.py +58 -0
- tsugite_cli-0.8.2/tests/test_skill_discovery.py +403 -0
- tsugite_cli-0.8.2/tests/test_skill_tools.py +344 -0
- tsugite_cli-0.8.2/tests/test_stdin.py +204 -0
- tsugite_cli-0.8.2/tests/test_tmux_tools.py +397 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_tool_directives.py +5 -5
- tsugite_cli-0.8.2/tests/test_workspace_auto_continue.py +74 -0
- tsugite_cli-0.8.2/tests/test_workspace_cwd.py +370 -0
- tsugite_cli-0.8.2/tests/test_workspace_discovery.py +120 -0
- tsugite_cli-0.8.2/tsugite/__init__.py +19 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/agent_inheritance.py +45 -68
- tsugite_cli-0.8.2/tsugite/agent_preparation.py +413 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/agent_runner/__init__.py +8 -2
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/agent_runner/helpers.py +37 -1
- tsugite_cli-0.8.2/tsugite/agent_runner/history_integration.py +270 -0
- tsugite_cli-0.8.2/tsugite/agent_runner/models.py +52 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/agent_runner/runner.py +426 -574
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/agent_runner/validation.py +3 -4
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/attachments/__init__.py +3 -3
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/attachments/auto_context.py +42 -12
- tsugite_cli-0.8.2/tsugite/attachments/base.py +65 -0
- tsugite_cli-0.8.2/tsugite/attachments/file.py +151 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/attachments/storage.py +1 -1
- tsugite_cli-0.8.2/tsugite/attachments/url.py +147 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/attachments/youtube.py +12 -5
- tsugite_cli-0.8.2/tsugite/builtin_agents/.gitkeep +0 -0
- tsugite_cli-0.8.2/tsugite/builtin_agents/code_searcher.md +54 -0
- tsugite_cli-0.8.2/tsugite/builtin_agents/default.md +230 -0
- tsugite_cli-0.8.2/tsugite/builtin_agents/file_searcher.md +201 -0
- tsugite_cli-0.8.2/tsugite/builtin_agents/onboard.md +53 -0
- tsugite_cli-0.8.2/tsugite/builtin_skills/.gitkeep +0 -0
- tsugite_cli-0.8.2/tsugite/builtin_skills/codebase_exploration.md +650 -0
- tsugite_cli-0.8.2/tsugite/builtin_skills/python_math.md +202 -0
- tsugite_cli-0.8.2/tsugite/builtin_skills/response_patterns.md +95 -0
- tsugite_cli-0.8.2/tsugite/builtin_skills/scheduling.md +268 -0
- tsugite_cli-0.8.2/tsugite/builtin_skills/skill_authoring.md +342 -0
- tsugite_cli-0.8.2/tsugite/builtin_skills/tsugite_agent_basics.md +469 -0
- tsugite_cli-0.8.2/tsugite/builtin_skills/tsugite_jinja_reference.md +439 -0
- tsugite_cli-0.8.2/tsugite/builtin_skills/tsugite_skill_basics.md +574 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/cache.py +169 -3
- tsugite_cli-0.8.2/tsugite/cli/__init__.py +66 -0
- tsugite_cli-0.8.2/tsugite/cli/chat.py +101 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/cli/config.py +34 -60
- tsugite_cli-0.8.2/tsugite/cli/daemon.py +681 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/cli/helpers.py +152 -49
- tsugite_cli-0.8.2/tsugite/cli/history.py +205 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/cli/init.py +40 -59
- tsugite_cli-0.8.2/tsugite/cli/plugins.py +77 -0
- tsugite_cli-0.8.2/tsugite/cli/render.py +213 -0
- tsugite_cli-0.8.2/tsugite/cli/run.py +702 -0
- tsugite_cli-0.8.2/tsugite/cli/serve.py +41 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/cli/tools.py +4 -2
- tsugite_cli-0.8.2/tsugite/cli/validate.py +144 -0
- tsugite_cli-0.8.2/tsugite/cli/workspace.py +273 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/config.py +102 -66
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/console.py +0 -5
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/core/__init__.py +1 -2
- tsugite_cli-0.8.2/tsugite/core/agent.py +1294 -0
- tsugite_cli-0.8.2/tsugite/core/claude_code.py +253 -0
- tsugite_cli-0.8.2/tsugite/core/content_blocks.py +72 -0
- tsugite_cli-0.8.2/tsugite/core/executor.py +380 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/core/memory.py +10 -1
- tsugite_cli-0.8.2/tsugite/core/proxy.py +211 -0
- tsugite_cli-0.8.2/tsugite/core/sandbox.py +239 -0
- tsugite_cli-0.8.2/tsugite/core/subprocess_executor.py +721 -0
- tsugite_cli-0.8.2/tsugite/daemon/__init__.py +6 -0
- tsugite_cli-0.8.2/tsugite/daemon/adapters/__init__.py +5 -0
- tsugite_cli-0.8.2/tsugite/daemon/adapters/base.py +655 -0
- tsugite_cli-0.8.2/tsugite/daemon/adapters/discord.py +685 -0
- tsugite_cli-0.8.2/tsugite/daemon/adapters/http.py +1775 -0
- tsugite_cli-0.8.2/tsugite/daemon/adapters/scheduler_adapter.py +312 -0
- tsugite_cli-0.8.2/tsugite/daemon/compaction_scheduler.py +131 -0
- tsugite_cli-0.8.2/tsugite/daemon/config.py +180 -0
- tsugite_cli-0.8.2/tsugite/daemon/gateway.py +422 -0
- tsugite_cli-0.8.2/tsugite/daemon/memory.py +329 -0
- tsugite_cli-0.8.2/tsugite/daemon/push.py +99 -0
- tsugite_cli-0.8.2/tsugite/daemon/scheduler.py +455 -0
- tsugite_cli-0.8.2/tsugite/daemon/session_runner.py +185 -0
- tsugite_cli-0.8.2/tsugite/daemon/session_store.py +506 -0
- tsugite_cli-0.8.2/tsugite/daemon/web/css/responsive.css +182 -0
- tsugite_cli-0.8.2/tsugite/daemon/web/css/styles.css +216 -0
- tsugite_cli-0.8.2/tsugite/daemon/web/css/theme.css +47 -0
- tsugite_cli-0.8.2/tsugite/daemon/web/icons/icon-192.png +0 -0
- tsugite_cli-0.8.2/tsugite/daemon/web/icons/icon-512-maskable.png +0 -0
- tsugite_cli-0.8.2/tsugite/daemon/web/icons/icon-512.png +0 -0
- tsugite_cli-0.8.2/tsugite/daemon/web/icons/screenshot-narrow.png +0 -0
- tsugite_cli-0.8.2/tsugite/daemon/web/icons/screenshot-wide.png +0 -0
- tsugite_cli-0.8.2/tsugite/daemon/web/index.html +1046 -0
- tsugite_cli-0.8.2/tsugite/daemon/web/js/api.js +54 -0
- tsugite_cli-0.8.2/tsugite/daemon/web/js/app.js +103 -0
- tsugite_cli-0.8.2/tsugite/daemon/web/js/utils.js +84 -0
- tsugite_cli-0.8.2/tsugite/daemon/web/js/views/conversations.js +742 -0
- tsugite_cli-0.8.2/tsugite/daemon/web/js/views/dashboard.js +76 -0
- tsugite_cli-0.8.2/tsugite/daemon/web/js/views/file-editor.js +83 -0
- tsugite_cli-0.8.2/tsugite/daemon/web/js/views/kvstore.js +79 -0
- tsugite_cli-0.8.2/tsugite/daemon/web/js/views/schedules.js +185 -0
- tsugite_cli-0.8.2/tsugite/daemon/web/js/views/webhooks.js +71 -0
- tsugite_cli-0.8.2/tsugite/daemon/web/js/views/workspace.js +119 -0
- tsugite_cli-0.8.2/tsugite/daemon/web/manifest.json +18 -0
- tsugite_cli-0.8.2/tsugite/daemon/web/sw.js +27 -0
- tsugite_cli-0.8.2/tsugite/daemon/webhook_store.py +74 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/events/__init__.py +17 -5
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/events/base.py +21 -12
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/events/events.py +105 -35
- tsugite_cli-0.8.2/tsugite/events/helpers.py +81 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/exceptions.py +2 -9
- tsugite_cli-0.8.2/tsugite/history/__init__.py +52 -0
- tsugite_cli-0.8.2/tsugite/history/models.py +133 -0
- tsugite_cli-0.8.2/tsugite/history/reconstruction.py +348 -0
- tsugite_cli-0.8.2/tsugite/history/storage.py +547 -0
- tsugite_cli-0.8.2/tsugite/hooks.py +482 -0
- tsugite_cli-0.8.2/tsugite/interaction.py +79 -0
- tsugite_cli-0.8.2/tsugite/kvstore/__init__.py +45 -0
- tsugite_cli-0.8.2/tsugite/kvstore/backend.py +13 -0
- tsugite_cli-0.8.2/tsugite/kvstore/sqlite.py +83 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/mcp_client.py +2 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/mcp_config.py +1 -1
- tsugite_cli-0.8.2/tsugite/mcp_server.py +144 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/md_agents.py +39 -71
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/models.py +26 -1
- tsugite_cli-0.8.2/tsugite/options.py +94 -0
- tsugite_cli-0.8.2/tsugite/plugins.py +102 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/renderer.py +67 -1
- tsugite_cli-0.8.2/tsugite/schemas/__init__.py +91 -0
- tsugite_cli-0.8.2/tsugite/schemas/agent.schema.json +224 -0
- tsugite_cli-0.8.2/tsugite/shell_tool_config.py +184 -0
- tsugite_cli-0.8.2/tsugite/skill_discovery.py +159 -0
- tsugite_cli-0.8.2/tsugite/templates/AGENTS.md +154 -0
- tsugite_cli-0.8.2/tsugite/templates/IDENTITY.md +23 -0
- tsugite_cli-0.8.2/tsugite/templates/MEMORY.md +23 -0
- tsugite_cli-0.8.2/tsugite/templates/USER.md +17 -0
- tsugite_cli-0.8.2/tsugite/templates/personas/casual-technical.md +26 -0
- tsugite_cli-0.8.2/tsugite/templates/personas/marvin.md +32 -0
- tsugite_cli-0.8.2/tsugite/templates/personas/minimal.md +9 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/tools/__init__.py +98 -28
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/tools/agents.py +53 -13
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/tools/fs.py +174 -62
- tsugite_cli-0.8.2/tsugite/tools/history.py +133 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/tools/http.py +58 -72
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/tools/interactive.py +110 -42
- tsugite_cli-0.8.2/tsugite/tools/kv.py +86 -0
- tsugite_cli-0.8.2/tsugite/tools/notify.py +76 -0
- tsugite_cli-0.8.2/tsugite/tools/schedule.py +435 -0
- tsugite_cli-0.8.2/tsugite/tools/sessions.py +205 -0
- tsugite_cli-0.8.2/tsugite/tools/shell.py +54 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/tools/shell_tools.py +0 -1
- tsugite_cli-0.8.2/tsugite/tools/skills.py +284 -0
- tsugite_cli-0.8.2/tsugite/tools/tmux.py +311 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/ui/__init__.py +0 -13
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/ui/base.py +101 -129
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/ui/chat.py +121 -38
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/ui/helpers.py +0 -28
- tsugite_cli-0.8.2/tsugite/ui/jsonl.py +175 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/ui/plain.py +26 -79
- tsugite_cli-0.8.2/tsugite/ui/repl_chat.py +300 -0
- tsugite_cli-0.8.2/tsugite/ui/repl_commands.py +388 -0
- tsugite_cli-0.8.2/tsugite/ui/repl_completer.py +201 -0
- tsugite_cli-0.8.2/tsugite/ui/repl_handler.py +411 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/ui_context.py +16 -2
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/utils.py +61 -88
- tsugite_cli-0.8.2/tsugite/workspace/__init__.py +28 -0
- tsugite_cli-0.8.2/tsugite/workspace/context.py +37 -0
- tsugite_cli-0.8.2/tsugite/workspace/models.py +285 -0
- tsugite_cli-0.8.2/tsugite/workspace/session.py +174 -0
- tsugite_cli-0.8.2/tsugite/workspace/templates.py +59 -0
- tsugite_cli-0.8.2/uv.lock +2959 -0
- tsugite_cli-0.3.3/AGENTS.md +0 -1356
- tsugite_cli-0.3.3/CLAUDE.md +0 -1
- tsugite_cli-0.3.3/Dockerfile.runtime +0 -11
- tsugite_cli-0.3.3/README.md +0 -64
- tsugite_cli-0.3.3/benchmarks/README.md +0 -14
- tsugite_cli-0.3.3/benchmarks/basic/echo.md +0 -27
- tsugite_cli-0.3.3/benchmarks/basic/echo.test.md +0 -33
- tsugite_cli-0.3.3/benchmarks/basic/hello_world.md +0 -27
- tsugite_cli-0.3.3/benchmarks/basic/hello_world.test.md +0 -33
- tsugite_cli-0.3.3/benchmarks/basic/json_formatter.md +0 -38
- tsugite_cli-0.3.3/benchmarks/basic/json_formatter.test.md +0 -36
- tsugite_cli-0.3.3/benchmarks/basic/list_maker.md +0 -33
- tsugite_cli-0.3.3/benchmarks/basic/list_maker.test.md +0 -39
- tsugite_cli-0.3.3/benchmarks/basic/simple_math.md +0 -32
- tsugite_cli-0.3.3/benchmarks/basic/simple_math.test.md +0 -33
- tsugite_cli-0.3.3/benchmarks/complex/creative_writing.md +0 -35
- tsugite_cli-0.3.3/benchmarks/complex/creative_writing.test.md +0 -60
- tsugite_cli-0.3.3/benchmarks/tools/file_read_tool.md +0 -12
- tsugite_cli-0.3.3/benchmarks/tools/file_read_tool.test.md +0 -33
- tsugite_cli-0.3.3/benchmarks/tools/file_write_read_tool.md +0 -14
- tsugite_cli-0.3.3/benchmarks/tools/file_write_read_tool.test.md +0 -33
- tsugite_cli-0.3.3/benchmarks/tools/file_write_tool.md +0 -12
- tsugite_cli-0.3.3/benchmarks/tools/file_write_tool.test.md +0 -39
- tsugite_cli-0.3.3/benchmarks/tools/fixtures/config.json +0 -1
- tsugite_cli-0.3.3/benchmarks/tools/fixtures/data.txt +0 -3
- tsugite_cli-0.3.3/benchmarks/tools/fixtures/sample.txt +0 -2
- tsugite_cli-0.3.3/benchmarks/tools/shell_command_tool.md +0 -12
- tsugite_cli-0.3.3/benchmarks/tools/shell_command_tool.test.md +0 -32
- tsugite_cli-0.3.3/docs/examples/agents/morning_brief.md +0 -86
- tsugite_cli-0.3.3/docs/examples/agents/research_coordinator.md +0 -57
- tsugite_cli-0.3.3/docs/examples/agents/system_monitor.md +0 -54
- tsugite_cli-0.3.3/docs/examples/agents/web_searcher.md +0 -49
- tsugite_cli-0.3.3/docs/test_agents/prefresh_readme.md +0 -16
- tsugite_cli-0.3.3/docs/test_agents/template_test.md +0 -14
- tsugite_cli-0.3.3/docs/test_agents/test_agent.md +0 -15
- tsugite_cli-0.3.3/docs/test_agents/test_steps.md +0 -8
- tsugite_cli-0.3.3/tests/fixtures/agents/failing.md +0 -13
- tsugite_cli-0.3.3/tests/fixtures/agents/nested.md +0 -12
- tsugite_cli-0.3.3/tests/fixtures/agents/simple.md +0 -12
- tsugite_cli-0.3.3/tests/fixtures/agents/slow.md +0 -12
- tsugite_cli-0.3.3/tests/test_agent_attachments.py +0 -127
- tsugite_cli-0.3.3/tests/test_agent_composition.py +0 -189
- tsugite_cli-0.3.3/tests/test_attachment_deduplication.py +0 -228
- tsugite_cli-0.3.3/tests/test_attachment_resolution.py +0 -184
- tsugite_cli-0.3.3/tests/test_attachments.py +0 -196
- tsugite_cli-0.3.3/tests/test_benchmark_core.py +0 -301
- tsugite_cli-0.3.3/tests/test_benchmark_evaluators.py +0 -333
- tsugite_cli-0.3.3/tests/test_benchmark_metrics.py +0 -265
- tsugite_cli-0.3.3/tests/test_benchmark_reports.py +0 -347
- tsugite_cli-0.3.3/tests/test_cache_control.py +0 -157
- tsugite_cli-0.3.3/tests/test_continuation.py +0 -510
- tsugite_cli-0.3.3/tests/test_docker_delegation.py +0 -236
- tsugite_cli-0.3.3/tests/test_edit_strategies.py +0 -293
- tsugite_cli-0.3.3/tests/test_history.py +0 -637
- tsugite_cli-0.3.3/tests/test_history_models.py +0 -346
- tsugite_cli-0.3.3/tests/test_http_tools.py +0 -109
- tsugite_cli-0.3.3/tests/test_llm_evaluator.py +0 -344
- tsugite_cli-0.3.3/tests/test_stdin.py +0 -243
- tsugite_cli-0.3.3/tests/test_task_tracking.py +0 -362
- tsugite_cli-0.3.3/tests/test_textual_chat.py +0 -428
- tsugite_cli-0.3.3/tsugite/__init__.py +0 -6
- tsugite_cli-0.3.3/tsugite/agent_composition.py +0 -163
- tsugite_cli-0.3.3/tsugite/agent_preparation.py +0 -236
- tsugite_cli-0.3.3/tsugite/agent_runner/history_integration.py +0 -248
- tsugite_cli-0.3.3/tsugite/attachments/base.py +0 -34
- tsugite_cli-0.3.3/tsugite/attachments/file.py +0 -51
- tsugite_cli-0.3.3/tsugite/attachments/url.py +0 -59
- tsugite_cli-0.3.3/tsugite/benchmark/__init__.py +0 -62
- tsugite_cli-0.3.3/tsugite/benchmark/config.py +0 -183
- tsugite_cli-0.3.3/tsugite/benchmark/core.py +0 -292
- tsugite_cli-0.3.3/tsugite/benchmark/discovery.py +0 -377
- tsugite_cli-0.3.3/tsugite/benchmark/evaluators.py +0 -671
- tsugite_cli-0.3.3/tsugite/benchmark/execution.py +0 -657
- tsugite_cli-0.3.3/tsugite/benchmark/metrics.py +0 -204
- tsugite_cli-0.3.3/tsugite/benchmark/reports.py +0 -420
- tsugite_cli-0.3.3/tsugite/benchmark/utils.py +0 -288
- tsugite_cli-0.3.3/tsugite/builtin_agents/chat-assistant.md +0 -53
- tsugite_cli-0.3.3/tsugite/builtin_agents/default.md +0 -140
- tsugite_cli-0.3.3/tsugite/builtin_agents.py +0 -5
- tsugite_cli-0.3.3/tsugite/cli/__init__.py +0 -1042
- tsugite_cli-0.3.3/tsugite/cli/benchmark.py +0 -663
- tsugite_cli-0.3.3/tsugite/cli/history.py +0 -193
- tsugite_cli-0.3.3/tsugite/core/agent.py +0 -774
- tsugite_cli-0.3.3/tsugite/core/executor.py +0 -300
- tsugite_cli-0.3.3/tsugite/docker_cli.py +0 -270
- tsugite_cli-0.3.3/tsugite/history/__init__.py +0 -29
- tsugite_cli-0.3.3/tsugite/history/index.py +0 -210
- tsugite_cli-0.3.3/tsugite/history/models.py +0 -106
- tsugite_cli-0.3.3/tsugite/history/storage.py +0 -157
- tsugite_cli-0.3.3/tsugite/shell_tool_config.py +0 -265
- tsugite_cli-0.3.3/tsugite/templates/assistant.md +0 -14
- tsugite_cli-0.3.3/tsugite/tools/edit_strategies.py +0 -393
- tsugite_cli-0.3.3/tsugite/tools/shell.py +0 -129
- tsugite_cli-0.3.3/tsugite/tools/tasks.py +0 -339
- tsugite_cli-0.3.3/tsugite/ui/chat.tcss +0 -92
- tsugite_cli-0.3.3/tsugite/ui/chat_history.py +0 -286
- tsugite_cli-0.3.3/tsugite/ui/jsonl.py +0 -125
- tsugite_cli-0.3.3/tsugite/ui/live_template.py +0 -529
- tsugite_cli-0.3.3/tsugite/ui/textual_chat.py +0 -642
- tsugite_cli-0.3.3/tsugite/ui/textual_handler.py +0 -225
- tsugite_cli-0.3.3/tsugite/ui/widgets/__init__.py +0 -6
- tsugite_cli-0.3.3/tsugite/ui/widgets/base_scroll_log.py +0 -27
- tsugite_cli-0.3.3/tsugite/ui/widgets/message_list.py +0 -121
- tsugite_cli-0.3.3/tsugite/ui/widgets/thought_log.py +0 -80
- tsugite_cli-0.3.3/tsugite/xdg.py +0 -104
- tsugite_cli-0.3.3/uv.lock +0 -2767
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/.github/workflows/ci.yml +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/.github/workflows/docker-publish.yml +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/.github/workflows/pypi-publish.yml +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/LICENSE +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/README.md +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/__init__.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/core/__init__.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/core/test_memory.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/core/test_tools.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/smoke_test.sh +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_agents_tool.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_chat_cli.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_cli_arguments.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_custom_shell_tools.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_error_display.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_interactive_tool.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_mcp_client.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_reasoning_models.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_renderer.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_retry_system.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_subagent_subprocess.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tests/test_tool_registry.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/agent_runner/metrics.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/agent_utils.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/attachments/inline.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/cli/agents.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/cli/attachments.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/cli/cache.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/cli/mcp.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/constants.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/core/tools.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/events/bus.py +0 -0
- {tsugite_cli-0.3.3 → tsugite_cli-0.8.2}/tsugite/tsugite.py +0 -0
|
@@ -7,19 +7,18 @@ Tsugite is a micro-agent CLI: agents are Markdown + YAML frontmatter, rendered v
|
|
|
7
7
|
**Flow:** `Agent.md` (YAML + Jinja2) → `renderer.py` → `TsugiteAgent` → LiteLLM → Tools
|
|
8
8
|
|
|
9
9
|
**Key Modules:**
|
|
10
|
-
- `cli/__init__.py` - Typer CLI (run, chat, render, config, mcp, tools, agents, attachments, cache
|
|
10
|
+
- `cli/__init__.py` - Typer CLI (run, chat, render, config, mcp, tools, agents, attachments, cache)
|
|
11
11
|
- `md_agents.py` - Parse frontmatter + agent resolution + directives
|
|
12
12
|
- `builtin_agents/` - File-based built-in agent definitions (default.md, chat-assistant.md)
|
|
13
13
|
- `agent_inheritance.py` - Agent resolution pipeline + inheritance chain
|
|
14
14
|
- `chat.py` - Chat session management with history
|
|
15
|
-
- `ui/textual_chat.py` - Textual TUI for interactive chat
|
|
16
15
|
- `agent_runner.py` - Execution orchestration, prefetch, tool wiring, multi-step
|
|
17
16
|
- `core/agent.py` - LiteLLM agent loop + streaming
|
|
18
17
|
- `renderer.py` - Jinja2 rendering + helpers (now, today, slugify, env, file_exists, read_text, is_file, is_dir)
|
|
19
18
|
- `tools/` - Tool registry + implementations
|
|
20
19
|
- `shell_tool_config.py` + `tools/shell_tools.py` - Custom shell command wrappers
|
|
21
20
|
- `models.py` - Model string parsing + provider dispatch
|
|
22
|
-
- `config.py` - Configuration (default_model, model_aliases, default_base_agent
|
|
21
|
+
- `config.py` - Configuration (default_model, model_aliases, default_base_agent)
|
|
23
22
|
|
|
24
23
|
**Development:**
|
|
25
24
|
```bash
|
|
@@ -42,8 +41,9 @@ uv run black . && uv run ruff check .
|
|
|
42
41
|
File-based agents distributed with the package in `tsugite/builtin_agents/` directory.
|
|
43
42
|
|
|
44
43
|
**Current Built-ins:**
|
|
45
|
-
1. `default.md` -
|
|
46
|
-
2. `
|
|
44
|
+
1. `default.md` - General-purpose agent with task tracking, spawn_agent, file tools, web search, memory, and shell execution
|
|
45
|
+
2. `file_searcher.md` - Specialized agent for finding files and searching content
|
|
46
|
+
3. `code_searcher.md` - AST-based structural code search using ast-grep
|
|
47
47
|
|
|
48
48
|
**Location:** `tsugite/builtin_agents/{name}.md`
|
|
49
49
|
|
|
@@ -71,20 +71,17 @@ File-based agents distributed with the package in `tsugite/builtin_agents/` dire
|
|
|
71
71
|
|
|
72
72
|
**Components:**
|
|
73
73
|
- `chat.py:ChatManager` - Session management, history (max_history), turn execution
|
|
74
|
-
- `ui/
|
|
75
|
-
- `ui/widgets/` - MessageList, ThoughtLog
|
|
74
|
+
- `ui/repl_chat.py` - REPL chat interface
|
|
76
75
|
|
|
77
|
-
**Default Agent:** `
|
|
76
|
+
**Default Agent:** `default`. Override with `.tsugite/default.md`.
|
|
78
77
|
|
|
79
78
|
**Flow:**
|
|
80
79
|
1. User input → `ChatManager.run_turn()`
|
|
81
80
|
2. Inject `chat_history` context (list of ChatTurn objects)
|
|
82
|
-
3. Call `agent_runner.run_agent()`
|
|
81
|
+
3. Call `agent_runner.run_agent()`
|
|
83
82
|
4. Store result in ChatTurn (timestamp, messages, token_count, cost)
|
|
84
83
|
5. Prune history if `> max_history`
|
|
85
84
|
|
|
86
|
-
**Text Mode:** `text_mode: true` allows LLM responses without code blocks.
|
|
87
|
-
|
|
88
85
|
### Directives
|
|
89
86
|
|
|
90
87
|
**Types:**
|
|
@@ -155,7 +152,6 @@ Chat:
|
|
|
155
152
|
---
|
|
156
153
|
name: my_chat
|
|
157
154
|
model: openai:gpt-4o
|
|
158
|
-
text_mode: true
|
|
159
155
|
tools: [read_file, web_search]
|
|
160
156
|
---
|
|
161
157
|
{% if chat_history %}
|
|
@@ -166,4 +166,14 @@ cython_debug/
|
|
|
166
166
|
.env
|
|
167
167
|
benchmark_results/
|
|
168
168
|
test_output/
|
|
169
|
-
.claude/settings.local.json
|
|
169
|
+
.claude/settings.local.json
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
# TODO: temp - I need to clean up the docs
|
|
173
|
+
docs/
|
|
174
|
+
examples/
|
|
175
|
+
agents/
|
|
176
|
+
.claude/
|
|
177
|
+
.tsugite/
|
|
178
|
+
benchmarks/
|
|
179
|
+
#### TODO ^^^
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to AI agents (tsugite, Claude Code, etc.) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
### Development Setup
|
|
8
|
+
```bash
|
|
9
|
+
# Install dependencies
|
|
10
|
+
uv sync --dev
|
|
11
|
+
|
|
12
|
+
# Run all tests
|
|
13
|
+
uv run pytest
|
|
14
|
+
|
|
15
|
+
# Run specific test
|
|
16
|
+
uv run pytest tests/test_file.py::test_function
|
|
17
|
+
|
|
18
|
+
# Run tests with coverage
|
|
19
|
+
uv run pytest --cov=tsugite --cov-report=html
|
|
20
|
+
|
|
21
|
+
# Lint and format
|
|
22
|
+
uv run black .
|
|
23
|
+
uv run ruff check .
|
|
24
|
+
uv run pylint tsugite
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Testing Agents
|
|
28
|
+
```bash
|
|
29
|
+
# Run a basic agent (both `tsugite` and `tsu` aliases work)
|
|
30
|
+
uv run tsugite run examples/simple_variable_injection.md "test task"
|
|
31
|
+
|
|
32
|
+
# Run with specific model
|
|
33
|
+
uv run tsu run +agent "task" --model openai:gpt-4o-mini
|
|
34
|
+
|
|
35
|
+
# Preview agent rendering (see what LLM receives)
|
|
36
|
+
uv run tsu render agent.md "task"
|
|
37
|
+
|
|
38
|
+
# Validate agent schema
|
|
39
|
+
uv run tsu validate agents/*.md
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Schema Management
|
|
43
|
+
```bash
|
|
44
|
+
# Regenerate JSON schema after modifying AgentConfig
|
|
45
|
+
uv run python scripts/regenerate_schema.py
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Architecture
|
|
49
|
+
|
|
50
|
+
Tsugite is an agentic CLI that executes AI agents defined as markdown files with YAML frontmatter. The architecture follows a pipeline pattern: parse → prepare → render → execute.
|
|
51
|
+
|
|
52
|
+
### Core Execution Flow
|
|
53
|
+
|
|
54
|
+
1. **CLI Entry** (`tsugite/cli/__init__.py`)
|
|
55
|
+
- Typer-based CLI with subcommands
|
|
56
|
+
- Main commands: `run` (single-shot), `chat` (interactive), `render` (preview)
|
|
57
|
+
- Additional: `daemon`, `workspace`, `init`, `validate`, `mcp`, `serve`, `agents`, `config`, `attachments`, `cache`, `tools`, `history`
|
|
58
|
+
|
|
59
|
+
2. **Agent Resolution & Inheritance** (`tsugite/agent_inheritance.py`)
|
|
60
|
+
- Resolves agent names to file paths using search order:
|
|
61
|
+
- Workspace agents directory (if workspace provided)
|
|
62
|
+
- `.tsugite/{name}.md` (project-local)
|
|
63
|
+
- `agents/{name}.md` (project convention)
|
|
64
|
+
- `./{name}.md` (current directory)
|
|
65
|
+
- `builtin_agents/{name}.md` (package-provided)
|
|
66
|
+
- Global directories (`~/.config/tsugite/agents/`)
|
|
67
|
+
- Merges agent inheritance chains (scalars override, lists merge, dicts deep merge)
|
|
68
|
+
|
|
69
|
+
3. **Agent Parsing** (`tsugite/md_agents.py`)
|
|
70
|
+
- Parses YAML frontmatter → `AgentConfig` (Pydantic model)
|
|
71
|
+
- Extracts markdown content
|
|
72
|
+
- Parses directives:
|
|
73
|
+
- `<!-- tsu:step -->` - Multi-step workflow stages
|
|
74
|
+
- `<!-- tsu:ignore -->` - Documentation blocks (stripped before LLM)
|
|
75
|
+
- `<!-- tsu:tool -->` - Execute tools during rendering
|
|
76
|
+
|
|
77
|
+
4. **Agent Preparation** (`tsugite/agent_preparation.py`)
|
|
78
|
+
- **Unified preparation pipeline** (used by both `run` and `render` commands)
|
|
79
|
+
- Executes prefetch tools (frontmatter `prefetch` field)
|
|
80
|
+
- Executes tool directives (inline `<!-- tsu:tool -->`)
|
|
81
|
+
- Builds template context (tasks, variables, helpers)
|
|
82
|
+
- Renders Jinja2 templates
|
|
83
|
+
- Expands tool globs and categories
|
|
84
|
+
- Loads auto_load_skills
|
|
85
|
+
- Builds system prompt with tools and instructions
|
|
86
|
+
|
|
87
|
+
5. **Template Rendering** (`tsugite/renderer.py`)
|
|
88
|
+
- Jinja2 environment with custom helpers:
|
|
89
|
+
- `{{ user_prompt }}`, `{{ tasks }}`, `{{ task_summary }}`
|
|
90
|
+
- `{{ now() }}`, `{{ today() }}`, `{{ yesterday() }}`, `{{ tomorrow() }}`
|
|
91
|
+
- `{{ slugify(text) }}`, `{{ cwd() }}`
|
|
92
|
+
- `{{ file_exists(path) }}`, `{{ is_file(path) }}`, `{{ is_dir(path) }}`, `{{ read_text(path) }}`
|
|
93
|
+
- Context also includes: `env` (os.environ), `datetime`, `timedelta`
|
|
94
|
+
- Supports step-scoped variables for multi-step agents
|
|
95
|
+
- Strips ignored sections before LLM execution
|
|
96
|
+
|
|
97
|
+
6. **Agent Execution** (`tsugite/agent_runner/runner.py`)
|
|
98
|
+
- Orchestrates multi-step or single-step execution
|
|
99
|
+
- Manages step metrics (duration, success/failure)
|
|
100
|
+
- Handles looping steps (repeat_while/repeat_until)
|
|
101
|
+
- Supports continue_on_error and per-step timeouts
|
|
102
|
+
- Integrates with history system for conversation continuity
|
|
103
|
+
|
|
104
|
+
7. **LLM Agent Loop** (`tsugite/core/agent.py`)
|
|
105
|
+
- `TsugiteAgent` - Custom agent using LiteLLM directly
|
|
106
|
+
- Think-Code-Observation loop (max_turns iterations)
|
|
107
|
+
- Supports reasoning models (o1, o3, Claude extended thinking)
|
|
108
|
+
- Direct control over model parameters (temperature, reasoning_effort)
|
|
109
|
+
- Code execution via `LocalExecutor`
|
|
110
|
+
|
|
111
|
+
8. **Tool System** (`tsugite/tools/`)
|
|
112
|
+
- Tool registry with built-in tools (fs, http, shell, tasks, agents, memory, skills, history, interactive)
|
|
113
|
+
- Category system: `@fs`, `@http`, `@shell`, `@tasks`, `@agents`, `@memory`, `@skills`, `@history`, `@interactive`
|
|
114
|
+
- Custom shell tools (config-based command wrappers)
|
|
115
|
+
- MCP integration (`tsugite/mcp_client.py`)
|
|
116
|
+
- Tool expansion supports globs (`*_search`) and exclusions (`-delete_file`)
|
|
117
|
+
|
|
118
|
+
9. **Event System** (`tsugite/events/`)
|
|
119
|
+
- Event-driven architecture for UI decoupling
|
|
120
|
+
- 20 event types: execution, LLM, meta, progress, skills
|
|
121
|
+
- `EventBus` dispatches to multiple handlers
|
|
122
|
+
- Handlers: Rich console, plain text, JSONL, chat, REPL
|
|
123
|
+
|
|
124
|
+
10. **History System** (`tsugite/history/`)
|
|
125
|
+
- JSONL-based conversation history (one `.jsonl` file per conversation)
|
|
126
|
+
- Stores turns (user prompts, assistant responses)
|
|
127
|
+
- Supports continuation (`--continue` flag, optional `--conversation-id`)
|
|
128
|
+
- Indexed by conversation_id, agent_name, machine_name
|
|
129
|
+
|
|
130
|
+
11. **Configuration** (`tsugite/config.py`)
|
|
131
|
+
- XDG-compliant paths: `~/.config/tsugite/` or `$XDG_CONFIG_HOME/tsugite/`
|
|
132
|
+
- JSON config with model aliases, default settings
|
|
133
|
+
- Attachment storage (reusable context)
|
|
134
|
+
- MCP server registration
|
|
135
|
+
- Auto-context discovery (CLAUDE.md, AGENTS.md, CONTEXT.md)
|
|
136
|
+
|
|
137
|
+
### Key Data Structures
|
|
138
|
+
|
|
139
|
+
**AgentConfig** (`md_agents.py:43`)
|
|
140
|
+
- Pydantic model for agent frontmatter
|
|
141
|
+
- Validates all fields (name, model, tools, max_turns, etc.)
|
|
142
|
+
- Schema exported to `tsugite/schemas/agent.schema.json`
|
|
143
|
+
|
|
144
|
+
**PreparedAgent** (`agent_preparation.py:17`)
|
|
145
|
+
- Dataclass containing everything for execution/display
|
|
146
|
+
- Ensures `render` shows exactly what `run` executes
|
|
147
|
+
- Contains: agent, config, system_message, user_message, tools, context
|
|
148
|
+
|
|
149
|
+
**Tool** (`core/tools.py`)
|
|
150
|
+
- Unified tool interface for LLM function calling
|
|
151
|
+
- Supports async/sync execution
|
|
152
|
+
- Parameters with JSON schema validation
|
|
153
|
+
|
|
154
|
+
**Agent** (`md_agents.py`)
|
|
155
|
+
- Parsed agent with content and step directives
|
|
156
|
+
- Steps contain: name, assign variable, temperature, timeout, continue_on_error, repeat conditions
|
|
157
|
+
|
|
158
|
+
### Multi-Step Agents
|
|
159
|
+
|
|
160
|
+
Multi-step agents use `<!-- tsu:step -->` directives to create workflows:
|
|
161
|
+
|
|
162
|
+
```markdown
|
|
163
|
+
<!-- tsu:step name="research" assign="findings" timeout="60" -->
|
|
164
|
+
Research topic
|
|
165
|
+
|
|
166
|
+
<!-- tsu:step name="summarize" assign="summary" repeat_while="has_pending_tasks" -->
|
|
167
|
+
Summarize findings
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Step Execution:**
|
|
171
|
+
- Preamble (content before first step) rendered once, shared across steps
|
|
172
|
+
- Each step has isolated execution context
|
|
173
|
+
- Variables persist across steps (findings → summary)
|
|
174
|
+
- Supports timeouts, continue_on_error, repeat conditions
|
|
175
|
+
- Metrics tracked per step (duration, status, errors)
|
|
176
|
+
|
|
177
|
+
**Looping Steps:**
|
|
178
|
+
- `repeat_while` / `repeat_until` with Jinja2 conditions
|
|
179
|
+
- Helper conditions: `has_pending_tasks`, `all_tasks_complete`, etc.
|
|
180
|
+
- Safety: `max_iterations` (default 10) prevents infinite loops
|
|
181
|
+
- Loop context: `{{ iteration }}`, `{{ max_iterations }}`, `{{ is_looping_step }}`
|
|
182
|
+
|
|
183
|
+
### Event-Driven UI
|
|
184
|
+
|
|
185
|
+
All UI output goes through the event system:
|
|
186
|
+
|
|
187
|
+
**Event Types** (events/base.py:9):
|
|
188
|
+
- Execution: TASK_START, STEP_START, CODE_EXECUTION, OBSERVATION, FINAL_ANSWER, ERROR
|
|
189
|
+
- LLM: LLM_MESSAGE, REASONING_CONTENT, REASONING_TOKENS
|
|
190
|
+
- Meta: COST_SUMMARY, STREAM_CHUNK, STREAM_COMPLETE, INFO, WARNING, DEBUG_MESSAGE
|
|
191
|
+
- Skills: SKILL_LOADED, SKILL_UNLOADED, SKILL_LOAD_FAILED
|
|
192
|
+
- Progress: STEP_PROGRESS, FILE_READ
|
|
193
|
+
|
|
194
|
+
**Handlers** (ui/):
|
|
195
|
+
- `base.py` - UIHandler interface
|
|
196
|
+
- `plain.py` - Plain text (no colors, copy-paste friendly)
|
|
197
|
+
- `jsonl.py` - JSONL protocol (for subprocess subagents)
|
|
198
|
+
- `chat.py`, `repl_handler.py` - Interactive chat/REPL modes
|
|
199
|
+
|
|
200
|
+
### Agent Spawning (Multi-Agent)
|
|
201
|
+
|
|
202
|
+
Agents can spawn other agents using the `spawn_agent` tool:
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
# Multi-agent mode: primary +helper1 +helper2
|
|
206
|
+
tsugite run +coordinator +researcher +writer "task"
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**Visibility control:**
|
|
210
|
+
- `visibility: public` (default) - Can be spawned by any agent
|
|
211
|
+
- `visibility: private` - Requires explicit allow list (multi-agent mode)
|
|
212
|
+
- `visibility: internal` - Helper agents, not meant to be public
|
|
213
|
+
- `spawnable: false` - Hard block, cannot be spawned (safety)
|
|
214
|
+
|
|
215
|
+
**Subagent context:**
|
|
216
|
+
- `{{ is_subagent }}` - Boolean
|
|
217
|
+
- `{{ parent_agent }}` - Parent agent name
|
|
218
|
+
|
|
219
|
+
### Prompt Caching
|
|
220
|
+
|
|
221
|
+
Automatic caching for supported providers (OpenAI, Anthropic, Bedrock, Deepseek):
|
|
222
|
+
|
|
223
|
+
- Attachments sent as separate system content blocks with `cache_control` markers
|
|
224
|
+
- Skills also receive cache markers for reuse across turns
|
|
225
|
+
- Cache markers added automatically by `tsugite/core/agent.py`
|
|
226
|
+
|
|
227
|
+
### Context Management (Daemon Mode)
|
|
228
|
+
|
|
229
|
+
When using Claude Code as the LLM provider for daemon mode, disable Claude Code's built-in auto-compaction so that tsugite's compaction logic (80% threshold) can manage context properly. If Claude Code compacts first, tsugite's compaction never triggers and session summaries are lost.
|
|
230
|
+
|
|
231
|
+
### Multi-Modal Attachments
|
|
232
|
+
|
|
233
|
+
Tsugite supports vision (images), audio, and document understanding through the attachment system.
|
|
234
|
+
|
|
235
|
+
**Supported Content Types:**
|
|
236
|
+
- **Images**: JPEG, PNG, GIF, WebP, SVG, BMP, TIFF
|
|
237
|
+
- **Audio**: MP3, WAV, OGG, M4A, FLAC (base64 encoded)
|
|
238
|
+
- **Documents**: PDF, Word (DOCX/DOC), Excel (XLSX/XLS), PowerPoint (PPTX/PPT)
|
|
239
|
+
- **Text**: Plain text, HTML (converted to markdown), JSON, XML, etc.
|
|
240
|
+
|
|
241
|
+
**How It Works:**
|
|
242
|
+
|
|
243
|
+
1. **URL Attachments** (Images/Documents):
|
|
244
|
+
- LiteLLM fetches the URL directly (no download overhead)
|
|
245
|
+
- Example: `tsu run -f https://example.com/chart.png "Describe this chart"`
|
|
246
|
+
- Automatically detected via HTTP HEAD request
|
|
247
|
+
|
|
248
|
+
2. **Local File Attachments**:
|
|
249
|
+
- Images: Read as bytes, base64 encoded
|
|
250
|
+
- Documents: Read as bytes, base64 encoded
|
|
251
|
+
- Text: Read as UTF-8
|
|
252
|
+
- Example: `tsu run -f image.jpg "What's in this image?"`
|
|
253
|
+
|
|
254
|
+
3. **LLM Integration**:
|
|
255
|
+
- Images: Sent as `image_url` content blocks (URL or data URI)
|
|
256
|
+
- Audio: Sent as `input_audio` content blocks (base64)
|
|
257
|
+
- Documents: Sent as `file` content blocks (URL or data URI)
|
|
258
|
+
- Text: Sent as `text` content blocks (wrapped in XML tags)
|
|
259
|
+
|
|
260
|
+
**Examples:**
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
# Analyze an image from URL
|
|
264
|
+
tsu run -f https://example.com/chart.png "Describe this chart"
|
|
265
|
+
|
|
266
|
+
# Analyze a local image
|
|
267
|
+
tsu run -f screenshot.png "What error is shown?"
|
|
268
|
+
|
|
269
|
+
# Analyze a PDF
|
|
270
|
+
tsu run -f report.pdf "Summarize this report"
|
|
271
|
+
|
|
272
|
+
# Multiple attachments
|
|
273
|
+
tsu run -f image1.jpg -f image2.jpg "Compare these images"
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**Model Support:**
|
|
277
|
+
- Vision: Claude 3.5 Sonnet, GPT-4o, GPT-4 Turbo, Gemini Pro Vision, etc.
|
|
278
|
+
- Audio: GPT-4o Audio Preview
|
|
279
|
+
- Documents: Claude (Bedrock/API), GPT-4o, Gemini, Bedrock Anthropic models
|
|
280
|
+
|
|
281
|
+
**Implementation Details:**
|
|
282
|
+
- `Attachment` dataclass: `tsugite/attachments/base.py`
|
|
283
|
+
- URL handler: `tsugite/attachments/url.py` (detects content type via HEAD request)
|
|
284
|
+
- File handler: `tsugite/attachments/file.py` (detects type by extension)
|
|
285
|
+
- Auto-context handler: `tsugite/attachments/auto_context.py` (discovers CONTEXT.md, AGENTS.md, CLAUDE.md)
|
|
286
|
+
- YouTube handler: `tsugite/attachments/youtube.py` (fetches transcripts)
|
|
287
|
+
- LLM formatting: `tsugite/core/agent.py:_format_attachment()`
|
|
288
|
+
|
|
289
|
+
## Development Patterns
|
|
290
|
+
|
|
291
|
+
### Adding a New Built-in Agent
|
|
292
|
+
|
|
293
|
+
1. Create `tsugite/builtin_agents/my_agent.md`
|
|
294
|
+
2. Add frontmatter with `name`, `tools`, `description`
|
|
295
|
+
3. Write agent template
|
|
296
|
+
4. No code changes needed - auto-discovered
|
|
297
|
+
5. Add tests in `tests/test_builtin_agents.py`
|
|
298
|
+
|
|
299
|
+
### Adding a New Tool
|
|
300
|
+
|
|
301
|
+
1. Create tool function in `tsugite/tools/`
|
|
302
|
+
2. Register in tool registry (`tools/__init__.py`)
|
|
303
|
+
3. Define parameters with JSON schema
|
|
304
|
+
4. Add to category if applicable (`@fs`, `@http`, etc.)
|
|
305
|
+
5. Add tests in `tests/test_*_tools.py`
|
|
306
|
+
|
|
307
|
+
### Adding a New Event Type
|
|
308
|
+
|
|
309
|
+
1. Add to `EventType` enum (`events/base.py`)
|
|
310
|
+
2. Create event class in `events/events.py`
|
|
311
|
+
3. Update UI handlers to handle new event
|
|
312
|
+
4. Add tests in `tests/events/`
|
|
313
|
+
|
|
314
|
+
### Modifying AgentConfig
|
|
315
|
+
|
|
316
|
+
1. Update `AgentConfig` Pydantic model (`md_agents.py`)
|
|
317
|
+
2. Regenerate schema: `uv run python scripts/regenerate_schema.py`
|
|
318
|
+
3. Update documentation in CLAUDE.md (user guide section)
|
|
319
|
+
4. Add validation tests in `tests/test_agent_parser.py`
|
|
320
|
+
|
|
321
|
+
## Testing Strategy
|
|
322
|
+
|
|
323
|
+
- **TDD preferred**: Write tests first when building new features. Tests don't need to be elaborate — simple tests that verify the expected behavior are enough. This creates a fast feedback loop and catches integration issues early (e.g., contextvar propagation, tool registration) before manual testing.
|
|
324
|
+
- **Unit tests**: Individual functions and classes
|
|
325
|
+
- **Pipeline tests**: Mock only `TsugiteAgent`/`litellm.acompletion` but exercise the full pipeline (parsing → rendering → preparation → tool expansion → execution). Most tests in the suite are this style.
|
|
326
|
+
- **Smoke tests**: `tests/smoke_test.sh` hits a real LLM API (requires `OPENAI_API_KEY`, not run in CI)
|
|
327
|
+
- **Fixtures**: `conftest.py` provides shared test data
|
|
328
|
+
- **Mocking**: Use `@pytest.fixture` for LLM responses
|
|
329
|
+
- **Async tests**: Mark with `@pytest.mark.asyncio`
|
|
330
|
+
- **Coverage target**: 80%+ (check with `--cov-report=html`)
|
|
331
|
+
|
|
332
|
+
## Code Style
|
|
333
|
+
|
|
334
|
+
- Python 3.11+ (type hints on public APIs)
|
|
335
|
+
- Line length: 120 characters (Black)
|
|
336
|
+
- Import order: stdlib → third-party → local (blank lines between groups)
|
|
337
|
+
- Errors: `ValueError` for input validation, `RuntimeError` for execution failures
|
|
338
|
+
- Docstrings: Google style with `Args:` and `Returns:` sections
|
|
339
|
+
- Pydantic models: Use `extra="forbid"` to catch typos in YAML frontmatter
|
|
340
|
+
|
|
341
|
+
## Common Pitfalls
|
|
342
|
+
|
|
343
|
+
1. **Don't break render/run parity**: Changes to rendering must update BOTH `renderer.py` and `agent_preparation.py`
|
|
344
|
+
2. **Don't emit print/console directly**: Use event system (`EventBus.emit()`)
|
|
345
|
+
3. **Don't forget schema regen**: After modifying `AgentConfig`, regenerate schema
|
|
346
|
+
4. **Don't hardcode paths**: Use XDG utilities (`get_xdg_config_path()`, etc.)
|
|
347
|
+
5. **Don't use blocking IO in async**: Use `asyncio.to_thread()` for sync tools
|
|
348
|
+
6. **Test both sync and async paths**: Many tools support both execution modes
|
|
349
|
+
7. **Don't embed prompts in adapters/code**: Use context variables + conditional blocks in `default.md` instead. Add new context vars in `_build_agent_context()` (base adapter) and default them in `agent_preparation.py`, then use `{% if var %}` in the agent template. This keeps all prompt content in one place and leverages the existing rendering pipeline.
|
|
350
|
+
|
|
351
|
+
## Code Review Policy
|
|
352
|
+
|
|
353
|
+
- **Automatically run the `code-simplifier:code-simplifier` agent** (via the Task tool) after implementing any changes, without waiting for the user to ask. This catches duplication, unnecessary complexity, and keeps the codebase DRY.
|
|
354
|
+
- When making implementation plans, include a final "simplify/review" step that uses the code-simplifier agent on all modified files.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
See [AGENTS.md](AGENTS.md) for project instructions.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tsugite-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.2
|
|
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
|
|
@@ -248,15 +248,23 @@ Requires-Dist: jinja2>=3.1
|
|
|
248
248
|
Requires-Dist: litellm>=1.77.7
|
|
249
249
|
Requires-Dist: mcp>=1.0
|
|
250
250
|
Requires-Dist: nest-asyncio>=1.6.0
|
|
251
|
+
Requires-Dist: pathspec>=0.11.0
|
|
252
|
+
Requires-Dist: portalocker>=2.8.0
|
|
253
|
+
Requires-Dist: prompt-toolkit>=3.0.43
|
|
251
254
|
Requires-Dist: pydantic>=2.12.3
|
|
252
255
|
Requires-Dist: pyyaml>=6.0
|
|
253
256
|
Requires-Dist: questionary>=2.1.1
|
|
254
257
|
Requires-Dist: rich>=13.0
|
|
255
|
-
Requires-Dist: ruff>=0.13.2
|
|
256
|
-
Requires-Dist: textual-autocomplete>=4.0.6
|
|
257
|
-
Requires-Dist: textual>=6.2.1
|
|
258
258
|
Requires-Dist: typer>=0.12
|
|
259
|
+
Requires-Dist: tzlocal>=5.3.1
|
|
259
260
|
Requires-Dist: youtube-transcript-api>=0.6.0
|
|
261
|
+
Provides-Extra: daemon
|
|
262
|
+
Requires-Dist: cronsim>=2.6; extra == 'daemon'
|
|
263
|
+
Requires-Dist: discord-py>=2.3.2; extra == 'daemon'
|
|
264
|
+
Requires-Dist: py-vapid>=1.9.0; extra == 'daemon'
|
|
265
|
+
Requires-Dist: pywebpush>=2.0.0; extra == 'daemon'
|
|
266
|
+
Requires-Dist: starlette>=0.36; extra == 'daemon'
|
|
267
|
+
Requires-Dist: uvicorn>=0.25; extra == 'daemon'
|
|
260
268
|
Description-Content-Type: text/markdown
|
|
261
269
|
|
|
262
270
|
# tsugite
|
|
@@ -265,12 +273,24 @@ Tsugite (Japanese: 継ぎ手, the art of joinery in woodworking) is a developer-
|
|
|
265
273
|
|
|
266
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).
|
|
267
275
|
|
|
268
|
-
##
|
|
276
|
+
## Installation
|
|
269
277
|
|
|
270
278
|
```bash
|
|
271
|
-
# Install
|
|
272
|
-
uv
|
|
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
|
+
```
|
|
273
288
|
|
|
289
|
+
**Note:** The package name is `tsugite-cli`, but the command is `tsugite` (or `tsu` for short).
|
|
290
|
+
|
|
291
|
+
## Quick Start
|
|
292
|
+
|
|
293
|
+
```bash
|
|
274
294
|
# Run an agent
|
|
275
295
|
tsugite run examples/simple_variable_injection.md "test it"
|
|
276
296
|
|
|
@@ -322,4 +342,89 @@ tsugite history list
|
|
|
322
342
|
tsugite history show CONV_ID
|
|
323
343
|
```
|
|
324
344
|
|
|
345
|
+
## Sandbox
|
|
346
|
+
|
|
347
|
+
Agent code can run inside a [bubblewrap](https://github.com/containers/bubblewrap) sandbox with filesystem and network isolation.
|
|
348
|
+
|
|
349
|
+
```bash
|
|
350
|
+
# Sandbox with specific domains allowed
|
|
351
|
+
tsu run +default "task" --sandbox --allow-domain "github.com" --allow-domain "*.openai.com"
|
|
352
|
+
|
|
353
|
+
# Full network isolation
|
|
354
|
+
tsu run +default "task" --sandbox --no-network
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
**How it works:**
|
|
358
|
+
|
|
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
|
+
```
|
|
366
|
+
|
|
367
|
+
**Default mounts:**
|
|
368
|
+
|
|
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)
|
|
372
|
+
|
|
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.
|
|
374
|
+
|
|
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
|
|
379
|
+
|
|
380
|
+
**`--allow-domain` syntax:**
|
|
381
|
+
|
|
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 |
|
|
388
|
+
|
|
389
|
+
## Hooks
|
|
390
|
+
|
|
391
|
+
Hooks fire shell commands at lifecycle points. Configure in `.tsugite/hooks.yaml`:
|
|
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
|
+
```
|
|
413
|
+
|
|
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`).
|
|
415
|
+
|
|
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
|
+
|
|
421
|
+
## Development
|
|
422
|
+
|
|
423
|
+
```bash
|
|
424
|
+
# Clone and install for development
|
|
425
|
+
git clone https://github.com/justyns/tsugite.git
|
|
426
|
+
cd tsugite
|
|
427
|
+
uv sync --dev
|
|
428
|
+
```
|
|
429
|
+
|
|
325
430
|
See `examples/` for working agents and `CLAUDE.md` for AI-generated documentation.
|