ayder-cli 2.5.1__tar.gz → 2.5.3__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 (364) hide show
  1. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/AGENTS.md +92 -84
  2. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/PKG-INFO +16 -4
  3. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/README.md +15 -3
  4. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/docs/GATE.md +1 -1
  5. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/docs/PROJECT_STRUCTURE.md +14 -11
  6. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/docs/config.toml.example +3 -0
  7. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/pyproject.toml +1 -1
  8. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/agents/config.py +3 -1
  9. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/agents/runner.py +8 -0
  10. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/agents/tool.py +2 -1
  11. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/cli.py +14 -1
  12. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/cli_runner.py +1 -0
  13. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/config.py +9 -0
  14. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/context.py +9 -5
  15. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/session.py +12 -0
  16. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/skills.py +6 -5
  17. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/loops/chat_loop.py +152 -46
  18. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/process_manager.py +77 -48
  19. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/prompts.py +3 -0
  20. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/themes/ayder.py +17 -25
  21. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/themes/claude.py +17 -25
  22. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/context.py +4 -2
  23. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/context_definitions.py +2 -1
  24. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/filesystem.py +99 -21
  25. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/filesystem_definitions.py +8 -2
  26. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/note_tool.py +4 -2
  27. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/notes.py +4 -2
  28. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/notes_definitions.py +2 -1
  29. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/process_manager_definitions.py +2 -1
  30. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/search.py +4 -2
  31. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/search_definitions.py +2 -0
  32. ayder_cli-2.5.3/src/ayder_cli/tools/builtins/shell.py +146 -0
  33. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/shell_definitions.py +4 -1
  34. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/skill.py +18 -4
  35. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/skill_definitions.py +3 -1
  36. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/task_definitions.py +2 -1
  37. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/task_tool.py +56 -33
  38. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/tasks.py +44 -12
  39. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/utils_tools.py +4 -2
  40. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/web_definitions.py +2 -1
  41. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/definition.py +34 -1
  42. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/execution.py +4 -2
  43. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/mcp.py +28 -4
  44. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/__init__.py +11 -4
  45. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/app.py +39 -26
  46. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/screens.py +6 -0
  47. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/widgets.py +123 -17
  48. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/application/test_runtime_factory.py +1 -0
  49. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_session.py +32 -0
  50. ayder_cli-2.5.3/tests/loops/test_chat_loop_guards.py +282 -0
  51. ayder_cli-2.5.3/tests/loops/test_tool_batch_ordering.py +254 -0
  52. ayder_cli-2.5.3/tests/test_agents_md.py +114 -0
  53. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/test_cli.py +55 -0
  54. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/test_process_manager.py +2 -2
  55. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/test_prompts_environment.py +81 -1
  56. ayder_cli-2.5.3/tests/tools/test_bash_process_safety.py +198 -0
  57. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_bash_tool.py +34 -23
  58. ayder_cli-2.5.3/tests/tools/test_error_labels.py +103 -0
  59. ayder_cli-2.5.3/tests/tools/test_file_tool_output.py +182 -0
  60. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_impl.py +2 -2
  61. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_impl_coverage.py +5 -3
  62. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_mcp.py +21 -1
  63. ayder_cli-2.5.3/tests/tools/test_parallel_safe.py +91 -0
  64. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_path_security.py +2 -2
  65. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_skill_tool.py +43 -0
  66. ayder_cli-2.5.3/tests/tools/test_task_integrity.py +193 -0
  67. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_utils.py +3 -3
  68. ayder_cli-2.5.3/tests/tui/test_follow_mode.py +132 -0
  69. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_help_screen.py +26 -0
  70. ayder_cli-2.5.3/tests/tui/test_inline_sync_output.py +77 -0
  71. ayder_cli-2.5.3/tests/tui/test_mouse_support.py +20 -0
  72. ayder_cli-2.5.3/tests/tui/test_panel_layout.py +490 -0
  73. ayder_cli-2.5.3/tests/tui/test_real_turn_follow.py +260 -0
  74. ayder_cli-2.5.3/tests/tui/test_resume.py +162 -0
  75. ayder_cli-2.5.3/tests/tui/test_status_bar_cwd.py +185 -0
  76. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_confirm_screen.py +2 -0
  77. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/uv.lock +1 -1
  78. ayder_cli-2.5.1/docs/superpowers/plans/2026-06-26-file-editor-improvements.md +0 -771
  79. ayder_cli-2.5.1/docs/superpowers/plans/2026-06-26-session-save-resume.md +0 -1047
  80. ayder_cli-2.5.1/docs/superpowers/specs/2026-06-26-file-editor-improvements-design.md +0 -180
  81. ayder_cli-2.5.1/docs/superpowers/specs/2026-06-26-session-save-resume-design.md +0 -319
  82. ayder_cli-2.5.1/src/ayder_cli/tools/builtins/shell.py +0 -109
  83. ayder_cli-2.5.1/tests/tui/test_follow_mode.py +0 -38
  84. ayder_cli-2.5.1/tests/tui/test_resume.py +0 -86
  85. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/.github/workflows/ci.yml +0 -0
  86. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/.github/workflows/python-package.yml +0 -0
  87. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/.gitignore +0 -0
  88. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/.python-version +0 -0
  89. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/LICENSE +0 -0
  90. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/docs/README_AGENT_WORKFLOW.md +0 -0
  91. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/docs/README_OLLAMA.md +0 -0
  92. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/docs/cc.png +0 -0
  93. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/scripts/check_exception_handlers.py +0 -0
  94. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/scripts/check_log_arguments.py +0 -0
  95. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/scripts/check_logging_imports.py +0 -0
  96. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/scripts/exception_baseline.txt +0 -0
  97. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/scripts/find_percent_logging.py +0 -0
  98. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/scripts/log_argument_baseline.txt +0 -0
  99. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/scripts/logging_gates.py +0 -0
  100. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/__init__.py +0 -0
  101. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/__main__.py +0 -0
  102. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/agents/__init__.py +0 -0
  103. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/agents/callbacks.py +0 -0
  104. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/agents/registry.py +0 -0
  105. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/agents/run.py +0 -0
  106. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/agents/worktree.py +0 -0
  107. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/application/README.md +0 -0
  108. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/application/__init__.py +0 -0
  109. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/application/execution_policy.py +0 -0
  110. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/application/message_contract.py +0 -0
  111. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/application/runtime_factory.py +0 -0
  112. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/application/validation.py +0 -0
  113. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/cli_callbacks.py +0 -0
  114. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/console.py +0 -0
  115. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/cache_monitor.py +0 -0
  116. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/config_migration.py +0 -0
  117. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/context_manager.py +0 -0
  118. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/context_manager_factory.py +0 -0
  119. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/default_context_manager.py +0 -0
  120. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/ollama_context_manager.py +0 -0
  121. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/reasoning.py +0 -0
  122. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/result.py +0 -0
  123. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/diagnostics.py +0 -0
  124. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/log.py +0 -0
  125. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/logging_config.py +0 -0
  126. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/loops/__init__.py +0 -0
  127. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/masking.py +0 -0
  128. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/parser.py +0 -0
  129. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/__init__.py +0 -0
  130. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/base.py +0 -0
  131. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/evren.py +0 -0
  132. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/claude.py +0 -0
  133. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/deepseek.py +0 -0
  134. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/gemini.py +0 -0
  135. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/glm.py +0 -0
  136. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama.py +0 -0
  137. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama_drivers/__init__.py +0 -0
  138. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama_drivers/_errors.py +0 -0
  139. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama_drivers/base.py +0 -0
  140. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama_drivers/deepseek.py +0 -0
  141. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama_drivers/generic_native.py +0 -0
  142. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama_drivers/generic_xml.py +0 -0
  143. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama_drivers/matrix.py +0 -0
  144. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama_drivers/minimax.py +0 -0
  145. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama_drivers/qwen3.py +0 -0
  146. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama_drivers/registry.py +0 -0
  147. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama_inspector.py +0 -0
  148. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/openai.py +0 -0
  149. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/qwen.py +0 -0
  150. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/orchestrator.py +0 -0
  151. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/retry.py +0 -0
  152. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/services/__init__.py +0 -0
  153. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/services/interactions.py +0 -0
  154. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/services/messaging_inbox.py +0 -0
  155. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/skills/development-workflow/SKILL.md +0 -0
  156. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/themes/__init__.py +0 -0
  157. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/__init__.py +0 -0
  158. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/__init__.py +0 -0
  159. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/background_process_tool.py +0 -0
  160. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/utils_tools_definitions.py +0 -0
  161. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/web.py +0 -0
  162. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/hooks.py +0 -0
  163. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/mcp_client.py +0 -0
  164. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/normalization.py +0 -0
  165. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/plugin_api.py +0 -0
  166. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/plugin_github.py +0 -0
  167. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/plugin_manager.py +0 -0
  168. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/plugin_status.py +0 -0
  169. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/registry.py +0 -0
  170. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/schemas.py +0 -0
  171. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/utils.py +0 -0
  172. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/adapter.py +0 -0
  173. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/commands.py +0 -0
  174. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/helpers.py +0 -0
  175. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/keybindings.py +0 -0
  176. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/parser.py +0 -0
  177. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/rendering.py +0 -0
  178. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/theme_manager.py +0 -0
  179. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/types.py +0 -0
  180. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/ui.py +0 -0
  181. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/version.py +0 -0
  182. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/COVERAGE.md +0 -0
  183. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/__init__.py +0 -0
  184. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/__init__.py +0 -0
  185. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_agent_consolidated.py +0 -0
  186. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_agent_severity.py +0 -0
  187. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_agent_tools.py +0 -0
  188. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_callbacks.py +0 -0
  189. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_config.py +0 -0
  190. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_integration.py +0 -0
  191. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_queue.py +0 -0
  192. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_registry.py +0 -0
  193. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_run.py +0 -0
  194. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_runner.py +0 -0
  195. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_runner_provider_unavailable.py +0 -0
  196. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_tool.py +0 -0
  197. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_worktree_helpers.py +0 -0
  198. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_worktree_isolation.py +0 -0
  199. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/application/test_argument_canonicalization.py +0 -0
  200. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/application/test_execution_result_truthfulness.py +0 -0
  201. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/application/test_message_contract.py +0 -0
  202. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/client/test_main.py +0 -0
  203. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/conftest.py +0 -0
  204. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/convergence/__init__.py +0 -0
  205. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/convergence/test_execution_policy_parity.py +0 -0
  206. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/convergence/test_runtime_wiring.py +0 -0
  207. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/convergence/test_validation_path.py +0 -0
  208. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_asyncio_bridge.py +0 -0
  209. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_cache_monitor.py +0 -0
  210. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_config.py +0 -0
  211. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_config_coverage.py +0 -0
  212. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_config_migration.py +0 -0
  213. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_config_provider_logging.py +0 -0
  214. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_config_retry.py +0 -0
  215. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_config_skills.py +0 -0
  216. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_config_v2.py +0 -0
  217. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_context_manager_factory.py +0 -0
  218. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_default_config_evren.py +0 -0
  219. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_default_context_manager.py +0 -0
  220. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_default_context_manager_should_compact.py +0 -0
  221. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_default_context_newest_unit.py +0 -0
  222. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_default_context_skill_resupply.py +0 -0
  223. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_event_emission.py +0 -0
  224. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_event_stream.py +0 -0
  225. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_exception_guarantee.py +0 -0
  226. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_exception_hooks.py +0 -0
  227. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_log_facade.py +0 -0
  228. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_logging_config_keys.py +0 -0
  229. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_logging_sinks.py +0 -0
  230. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_loguru_caplog.py +0 -0
  231. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_max_output_tokens_default.py +0 -0
  232. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_ollama_compaction_persistence.py +0 -0
  233. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_ollama_context_manager.py +0 -0
  234. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_ollama_context_manager_cache_monitor.py +0 -0
  235. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_ollama_context_manager_max_history.py +0 -0
  236. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_ollama_skill_resupply.py +0 -0
  237. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_parameter_aliasing.py +0 -0
  238. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_parser.py +0 -0
  239. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_reasoning_config.py +0 -0
  240. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_scratch_dir.py +0 -0
  241. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_session_id_threading.py +0 -0
  242. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_sink_masking.py +0 -0
  243. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_skills.py +0 -0
  244. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_skills_builtin_sync.py +0 -0
  245. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/loops/__init__.py +0 -0
  246. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/loops/test_base.py +0 -0
  247. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/loops/test_chat_loop_hook.py +0 -0
  248. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/loops/test_chat_loop_tool_truncation.py +0 -0
  249. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/loops/test_loop_severity.py +0 -0
  250. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/loops/test_required_args_aliases.py +0 -0
  251. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/loops/test_tool_argument_integrity.py +0 -0
  252. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/loops/test_tool_batch_cancellation.py +0 -0
  253. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/__init__.py +0 -0
  254. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/__init__.py +0 -0
  255. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/test_base.py +0 -0
  256. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/test_deepseek.py +0 -0
  257. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/test_errors.py +0 -0
  258. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/test_fallback.py +0 -0
  259. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/test_generic_native.py +0 -0
  260. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/test_generic_xml.py +0 -0
  261. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/test_matrix.py +0 -0
  262. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/test_minimax.py +0 -0
  263. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/test_provider_integration.py +0 -0
  264. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/test_qwen3.py +0 -0
  265. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/test_registry.py +0 -0
  266. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_claude_stream_tool_calls.py +0 -0
  267. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_evren.py +0 -0
  268. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_gemini_function_calls.py +0 -0
  269. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_glm_async.py +0 -0
  270. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_ollama_inspector.py +0 -0
  271. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_ollama_native.py +0 -0
  272. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_ollama_parallel_tool_call_ids.py +0 -0
  273. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_ollama_xml.py +0 -0
  274. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_ollama_xml_autoroute.py +0 -0
  275. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_ollama_xml_usage.py +0 -0
  276. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_openai_list_models.py +0 -0
  277. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_orchestrator_capabilities.py +0 -0
  278. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_provider_channel_binding.py +0 -0
  279. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_provider_severity.py +0 -0
  280. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_qwen_async.py +0 -0
  281. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_reasoning_effort.py +0 -0
  282. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_retry_classifier.py +0 -0
  283. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_retry_integration.py +0 -0
  284. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_retrying_provider.py +0 -0
  285. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_skill_load_prefix.py +0 -0
  286. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/scripts/test_exception_gate.py +0 -0
  287. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/scripts/test_log_argument_gate.py +0 -0
  288. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/scripts/test_logging_policy_gates.py +0 -0
  289. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/scripts/test_loguru_private_shape.py +0 -0
  290. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/services/test_boundary.py +0 -0
  291. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/services/test_interaction_sink.py +0 -0
  292. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/services/test_messaging_inbox.py +0 -0
  293. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/test_cli_callbacks.py +0 -0
  294. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/test_context.py +0 -0
  295. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/test_env_manager.py +0 -0
  296. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/test_logging_config.py +0 -0
  297. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/test_notes.py +0 -0
  298. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/test_prompts_general.py +0 -0
  299. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/test_tasks.py +0 -0
  300. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/__init__.py +0 -0
  301. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_agent_notes.py +0 -0
  302. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_background_process_tool.py +0 -0
  303. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_context_storage_confinement.py +0 -0
  304. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_definition_discovery.py +0 -0
  305. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_di_injection.py +0 -0
  306. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_file_editor_hardening.py +0 -0
  307. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_file_editor_size_limit.py +0 -0
  308. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_mcp_client.py +0 -0
  309. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_note_tool.py +0 -0
  310. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_notes_api.py +0 -0
  311. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_notes_confinement.py +0 -0
  312. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_plugin_api.py +0 -0
  313. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_plugin_github.py +0 -0
  314. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_plugin_loading.py +0 -0
  315. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_plugin_manager.py +0 -0
  316. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_plugin_status.py +0 -0
  317. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_registry.py +0 -0
  318. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_registry_coverage.py +0 -0
  319. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_result.py +0 -0
  320. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_schemas.py +0 -0
  321. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_search_codebase.py +0 -0
  322. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_search_hardening.py +0 -0
  323. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_skill_catalog_and_filter.py +0 -0
  324. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_skill_scope_wiring.py +0 -0
  325. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_task_path_confinement.py +0 -0
  326. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_task_tool.py +0 -0
  327. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_tool_severity.py +0 -0
  328. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_unexpected_args.py +0 -0
  329. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_web.py +0 -0
  330. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/__init__.py +0 -0
  331. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_agent_list_screen.py +0 -0
  332. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_do_clear_coordination.py +0 -0
  333. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_evren_terms.py +0 -0
  334. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_input_box.py +0 -0
  335. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_keybindings.py +0 -0
  336. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_multi_select_screen.py +0 -0
  337. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_multiline_input.py +0 -0
  338. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_paste.py +0 -0
  339. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_peer_message_turn.py +0 -0
  340. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_pending_compact_consumer.py +0 -0
  341. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_pull_delivery.py +0 -0
  342. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_status_bar_badges.py +0 -0
  343. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_themes.py +0 -0
  344. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_turn_consumer.py +0 -0
  345. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_widgets.py +0 -0
  346. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_diff_preview.py +0 -0
  347. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_plugin_autoenable.py +0 -0
  348. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_provider_switch.py +0 -0
  349. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_run_tui_startup.py +0 -0
  350. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_assistant_sanitization.py +0 -0
  351. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_chat_loop.py +0 -0
  352. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_commands_agent.py +0 -0
  353. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_commands_effort.py +0 -0
  354. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_commands_logging.py +0 -0
  355. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_commands_plugin.py +0 -0
  356. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_commands_provider.py +0 -0
  357. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_commands_skill.py +0 -0
  358. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_helpers.py +0 -0
  359. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_system_prompt_no_structure.py +0 -0
  360. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_temporal_command.py +0 -0
  361. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_widgets.py +0 -0
  362. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_ui.py +0 -0
  363. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_ui_coverage.py +0 -0
  364. {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_ui_verbose.py +0 -0
@@ -50,115 +50,127 @@ This document provides coding standards, tool configurations, and workflows for
50
50
  ayder-cli/
51
51
  ├── src/ayder_cli/ # Main source code
52
52
  │ ├── cli.py # Entry point (argparse)
53
- │ ├── cli_runner.py # CLI command execution logic
54
- │ ├── cli_callbacks.py # CLI callback implementations
55
- │ ├── client.py # ChatSession helpers
53
+ │ ├── __main__.py # `python -m ayder_cli`
54
+ │ ├── cli_runner.py # Single-command (non-TUI) runs and task commands
55
+ │ ├── cli_callbacks.py # CliCallbacks (ChatCallbacks for plain terminal runs)
56
56
  │ ├── console.py # Rich console instance
57
57
  │ ├── version.py # Version info
58
- │ ├── logging_config.py # Loguru setup
58
+ │ ├── log.py # Channel-scoped loguru accessors
59
+ │ ├── logging_config.py # Loguru sinks + stdlib-logging bridge
60
+ │ ├── masking.py # Credential masking for log text
61
+ │ ├── diagnostics.py # Process-level exception capture
62
+ │ ├── parser.py # Unified LLM output parser (ContentProcessor)
63
+ │ ├── process_manager.py # Background processes (own process group, group kill)
64
+ │ ├── prompts.py # System prompt templates + environment section
65
+ │ ├── ui.py # Rich terminal UI helpers
59
66
  │ │
60
67
  │ ├── core/ # Core infrastructure
61
68
  │ │ ├── config.py # Pydantic config with validation
62
- │ │ ├── context.py # ProjectContext (path sandboxing)
63
- │ │ └── result.py # ToolSuccess/ToolError types
69
+ │ │ ├── config_migration.py # Config schema v2.0 migration
70
+ │ │ ├── context.py # ProjectContext (path sandboxing, scratch dir)
71
+ │ │ ├── result.py # ToolSuccess/ToolError types
72
+ │ │ ├── session.py # Save/restore TUI sessions (.ayder/sessions/)
73
+ │ │ ├── skills.py # Skill discovery, scope, load blocks, active set
74
+ │ │ ├── reasoning.py # Reasoning settings (think / reasoning_effort)
75
+ │ │ ├── context_manager.py # ContextManager protocol + shared helpers
76
+ │ │ ├── context_manager_factory.py # Picks the context manager per provider
77
+ │ │ ├── default_context_manager.py # Token-budget trimming (non-Ollama)
78
+ │ │ ├── ollama_context_manager.py # Cache-aware stable-prefix manager (Ollama)
79
+ │ │ └── cache_monitor.py # KV-cache hit detection
64
80
  │ │
65
81
  │ ├── agents/ # Multi-agent system
66
- │ │ ├── __init__.py # Package exports
82
+ │ │ ├── config.py # AgentConfig ([agents.<name>])
83
+ │ │ ├── registry.py # AgentRegistry (dispatch, queue, lifecycle)
84
+ │ │ ├── run.py # AgentRun (per-dispatch state the main LLM polls)
85
+ │ │ ├── runner.py # AgentRunner (one isolated ChatLoop per dispatch)
67
86
  │ │ ├── callbacks.py # AgentCallbacks (ChatCallbacks for agents)
68
- │ │ ├── config.py # AgentConfig (Pydantic model)
69
- │ │ ├── registry.py # AgentRegistry (lifecycle management)
70
- │ │ ├── runner.py # AgentRunner (isolated ChatLoop execution)
71
- │ │ ├── summary.py # AgentSummary (structured result)
72
- │ │ └── tool.py # call_agent tool definition + handler
87
+ │ │ ├── worktree.py # Git worktree isolation for agents
88
+ │ │ └── tool.py # The `agent` tool definition + handler
73
89
  │ │
74
90
  │ ├── application/ # Shared application layer (CLI + TUI)
75
- │ │ ├── execution_policy.py # ExecutionPolicy, PermissionDeniedError
76
- │ │ ├── message_contract.py # LLM message format contracts
77
- │ │ ├── runtime_factory.py # create_runtime() + create_agent_runtime()
78
- │ │ ├── temporal_contract.py # Temporal workflow contracts
79
- │ │ ├── temporal_metadata.py # Temporal metadata types
80
- │ │ └── validation.py # ValidationAuthority, SchemaValidator
91
+ │ │ ├── execution_policy.py # ExecutionPolicy, PermissionDeniedError
92
+ │ │ ├── message_contract.py # LLM message format contracts
93
+ │ │ ├── runtime_factory.py # create_runtime() + create_agent_runtime()
94
+ │ │ └── validation.py # ValidationAuthority, SchemaValidator
81
95
  │ │
82
- │ ├── loops/ # Shared agent loop + base classes
83
- │ │ ├── base.py # AgentLoopBase (iteration, checkpoint, routing)
84
- │ │ ├── chat_loop.py # ChatLoop (async LLM + tool execution loop)
85
- │ │ └── config.py # Shared LoopConfig dataclass
96
+ │ ├── loops/
97
+ │ │ └── chat_loop.py # ChatLoop, ChatLoopConfig, ChatCallbacks (the only loop)
86
98
  │ │
87
99
  │ ├── providers/ # LLM provider implementations
88
100
  │ │ ├── base.py # AIProvider protocol, NormalizedStreamChunk
89
- │ │ ├── orchestrator.py # Factory: create(config) → provider
101
+ │ │ ├── orchestrator.py # Factory: create(config) → provider
102
+ │ │ ├── retry.py # Retry wrapper (backoff + mid-stream recovery)
90
103
  │ │ ├── evren.py # evren gateway terms-of-use acceptance (/model)
91
104
  │ │ └── impl/ # Individual provider drivers
92
105
  │ │ ├── openai.py # OpenAIProvider (base for most drivers)
93
- │ │ ├── ollama.py # OllamaProvider (native + XML fallback)
106
+ │ │ ├── ollama.py # OllamaProvider (routes through ollama_drivers/)
107
+ │ │ ├── ollama_inspector.py # Model introspection + native tool-call probe
108
+ │ │ ├── ollama_drivers/ # Per-family Ollama chat drivers + resolution matrix
94
109
  │ │ ├── claude.py # ClaudeProvider (Anthropic SDK)
95
110
  │ │ ├── gemini.py # GeminiProvider (Google GenAI SDK)
96
111
  │ │ ├── deepseek.py # DeepSeekProvider (OpenAI-compatible)
97
112
  │ │ ├── qwen.py # QwenNativeProvider (DashScope SDK)
98
113
  │ │ └── glm.py # GLMNativeProvider (ZhipuAI SDK)
99
114
  │ │
100
- │ ├── services/ # Service layer
101
- │ │ └── interactions.py # InteractionSink protocol (LLM debug events)
115
+ │ ├── services/
116
+ │ │ ├── interactions.py # InteractionSink protocol (LLM debug events)
117
+ │ │ └── messaging_inbox.py # Unix-socket inbox for prompts from peer processes
102
118
  │ │
103
- │ ├── tools/ # Tool framework + implementations (25 tools)
119
+ │ ├── tools/ # Tool framework + built-in tools
104
120
  │ │ ├── definition.py # ToolDefinition dataclass + auto-discovery
105
- │ │ ├── registry.py # ToolRegistry (schema, execution, system prompts)
121
+ │ │ ├── registry.py # ToolRegistry (schemas, dispatch, system prompts)
106
122
  │ │ ├── schemas.py # OpenAI-format JSON schemas
107
- │ │ ├── execution.py # Tool execution engine
108
- │ │ ├── hooks.py # Hook/middleware system
109
- │ │ ├── normalization.py # Argument normalization + path resolution
123
+ │ │ ├── execution.py # Tool execution pipeline
124
+ │ │ ├── hooks.py # Middleware and execution callbacks
125
+ │ │ ├── normalization.py # Argument aliases, path resolution, coercion
110
126
  │ │ ├── utils.py # Tool utilities
127
+ │ │ ├── mcp.py # Built-in MCP tools from .ayder/mcp.json
128
+ │ │ ├── mcp_client.py # MCP sessions + synchronous dispatch bridge
129
+ │ │ ├── plugin_manager.py # Install/update/load external plugins
130
+ │ │ ├── plugin_api.py # Plugin API version checks
131
+ │ │ ├── plugin_github.py # Plugin download from GitHub
132
+ │ │ ├── plugin_status.py # Plugin status badges
111
133
  │ │ └── builtins/ # Built-in tool implementations
112
- │ │ ├── *_definitions.py # Distributed tool definitions (13 files)
113
- │ │ ├── filesystem.py # file_explorer, read_file, file_editor
114
- │ │ ├── python_editor.py # CST-based Python structural editor
115
- │ │ ├── search.py # search_codebase, get_project_structure
116
- │ │ ├── shell.py # run_shell_command
117
- │ │ ├── venv.py # Virtualenv management tools
118
- │ │ ├── utils_tools.py # manage_environment_vars
119
- │ │ ├── web.py # fetch_web
120
- │ │ ├── dbs_tool.py # DBS RAG API tool
121
- │ │ ├── temporal.py # Temporal workflow tool
122
- │ │ ├── tasks.py # Task management (.ayder/tasks/)
123
- │ │ ├── notes.py # Note management (.ayder/notes/)
124
- │ │ └── memory.py # Cross-session memory storage
134
+ │ │ ├── *_definitions.py # Tool definitions, auto-discovered
135
+ │ │ ├── filesystem.py # file_explorer, read_file, file_editor
136
+ │ │ ├── search.py # search_codebase
137
+ │ │ ├── utils_tools.py # get_project_structure, manage_environment_vars
138
+ │ │ ├── shell.py # bash
139
+ │ │ ├── background_process_tool.py # background_process
140
+ │ │ ├── context.py # context (stats, save/load, compact)
141
+ │ │ ├── note_tool.py # note
142
+ │ │ ├── notes.py # Note storage (.ayder/notes/)
143
+ │ │ ├── task_tool.py # task
144
+ │ │ ├── tasks.py # Task files (.ayder/tasks/)
145
+ │ │ ├── skill.py # skill
146
+ │ │ └── web.py # fetch_web
125
147
  │ │
126
148
  │ ├── tui/ # Textual TUI (main interface)
127
149
  │ │ ├── __init__.py # run_tui() entry point
128
150
  │ │ ├── app.py # AyderApp main application
129
- │ │ ├── chat_loop.py # Backward-compat re-exports → loops/chat_loop.py
130
- │ │ ├── commands.py # Slash command handlers (19 commands)
151
+ │ │ ├── commands.py # Slash command handlers
152
+ │ │ ├── keybindings.py # Keybinding registry
131
153
  │ │ ├── helpers.py # TUI helper functions
132
154
  │ │ ├── adapter.py # TUIInteractionSink (verbose debug)
133
- │ │ ├── parser.py # Message parsing
134
- │ │ ├── screens.py # Modal screens (confirm, select, permission, task edit)
155
+ │ │ ├── parser.py # Re-exports of the unified ContentProcessor
156
+ │ │ ├── rendering.py # Safe render helpers
157
+ │ │ ├── screens.py # Modal screens (confirm, select, permission, task edit, …)
135
158
  │ │ ├── theme_manager.py # Theme loading and CSS
136
159
  │ │ ├── types.py # MessageType, ConfirmResult
137
- │ │ └── widgets.py # ChatView, ToolPanel, CLIInputBar, StatusBar
160
+ │ │ └── widgets.py # ChatView, ToolPanel, CLIInputBar, StatusBar, …
138
161
  │ │
139
- │ ├── themes/ # TUI themes
140
- │ │ ├── __init__.py # Theme registry
141
- │ │ ├── claude.py # Claude theme CSS (default, RGB)
142
- │ │ └── ayder.py # ayder tokenised layout + ANSI/RGB palette overlay ([ui] palette)
162
+ │ ├── skills/ # Packaged built-in skills (development-workflow/SKILL.md)
143
163
  │ │
144
- │ ├── parser.py # XML/JSON tool call parser
145
- │ ├── process_manager.py # Background process management
146
- │ ├── prompts.py # System prompt templates
147
- │ └── ui.py # Rich terminal UI helpers
164
+ │ └── themes/ # TUI themes
165
+ │ ├── claude.py # Claude theme CSS (RGB)
166
+ │ └── ayder.py # ayder tokenised layout + ANSI/RGB palette ([ui] palette)
148
167
  │
149
- ├── tests/ # Test suite (998+ tests)
150
- │ ├── application/ # Application layer tests
151
- │ ├── core/ # Core tests
152
- │ ├── services/ # Services tests
153
- │ ├── tools/ # Tool tests
154
- │ ├── ui/ # TUI tests
155
- │ └── *.py # Top-level tests
156
- │
157
- ├── .ayder/ # Project-specific data (tasks, notes, memory, skills)
168
+ ├── tests/ # Test suite, mirrors src/ (agents/, core/, loops/, tools/, tui/, …)
169
+ ├── docs/ # GATE.md, PROJECT_STRUCTURE.md, config.toml.example, guides
170
+ ├── .ayder/ # Project data (tasks, notes, sessions, skills); gitignored
158
171
  ├── pyproject.toml # Project configuration
159
172
  ├── AGENTS.md # This file
160
- ├── README.md # Project overview
161
- └── .claude/ # Claude Code configuration + skills
173
+ └── README.md # Project overview
162
174
  ```
163
175
 
164
176
  ### Key Files Reference
@@ -167,14 +179,12 @@ ayder-cli/
167
179
  |------|---------|
168
180
  | `cli.py` | Entry point, argument parsing |
169
181
  | `tui/app.py` | Main TUI application (AyderApp) |
170
- | `tui/commands.py` | Slash command handlers (19 commands) |
182
+ | `tui/commands.py` | Slash command handlers |
171
183
  | `loops/chat_loop.py` | Async LLM + tool execution loop (ChatLoop + ChatCallbacks protocol) |
172
- | `tui/chat_loop.py` | Backward-compat re-exports (TuiChatLoop → ChatLoop aliases) |
173
- | `cli_runner.py` | CLI command execution + sync agent loop |
184
+ | `cli_runner.py` | Single-command (non-TUI) runs |
174
185
  | `application/runtime_factory.py` | `create_runtime()` — single composition root for CLI + TUI |
175
186
  | `application/execution_policy.py` | Shared permission + tool execution policy |
176
187
  | `application/validation.py` | ValidationAuthority + SchemaValidator (single validation path) |
177
- | `loops/base.py` | AgentLoopBase shared by CLI and TUI loops |
178
188
  | `tools/definition.py` | ToolDefinition dataclass + auto-discovery from `*_definitions.py` |
179
189
  | `tools/registry.py` | ToolRegistry: schemas, execution, system prompts, tag filtering |
180
190
  | `core/config.py` | Configuration with Pydantic validation |
@@ -183,7 +193,7 @@ ayder-cli/
183
193
  | `providers/impl/ollama_drivers/` | Per-family Ollama chat-driver package (matrix, registry, drivers, error classifier) |
184
194
  | `providers/impl/ollama_inspector.py` | `OllamaInspector` with `probe_native_tool_calling()` for empirical model verification |
185
195
  | `docs/README_OLLAMA.md` | **Ollama tool-call compatibility guide.** Read before adding/changing any matrix routing for an Ollama model. Covers the `OllamaInspector.probe_native_tool_calling()` API, equivalent `curl` recipes, the markup-leak detection table, and the decision flow for new families. |
186
- | `docs/superpowers/specs/2026-05-02-ollama-chat-drivers-design.md` | Design spec for the per-family Ollama chat-drivers architecture. |
196
+ | `docs/GATE.md` | The gate procedure every PR's final SHA passes |
187
197
 
188
198
  ## Environment Setup
189
199
 
@@ -431,7 +441,7 @@ class TestFeature:
431
441
 
432
442
  ### Runtime Factory
433
443
 
434
- `application/runtime_factory.py` provides `create_runtime()` — the single composition root used by both CLI and TUI. It assembles a `RuntimeComponents` dataclass containing: `config`, `llm_provider`, `process_manager`, `project_ctx`, `tool_registry`, `memory_manager`, `system_prompt`.
444
+ `application/runtime_factory.py` provides `create_runtime()` — the single composition root used by both CLI and TUI. It assembles a `RuntimeComponents` dataclass containing: `config`, `llm_provider`, `process_manager`, `project_ctx`, `tool_registry`, `system_prompt`, `context_manager`, `environment_prompt`.
435
445
 
436
446
  ### Pluggable Tool System
437
447
 
@@ -460,23 +470,21 @@ TOOL_DEFINITIONS: tuple[ToolDefinition, ...] = (
460
470
  )
461
471
  ```
462
472
 
463
- **Current Tools (25 total):**
473
+ **Built-in Tools** (plugins and MCP servers add more at runtime; `tests/test_agents_md.py` keeps this table in step with the registry):
464
474
 
465
475
  | Category | Tag | Tools |
466
476
  |----------|-----|-------|
467
477
  | **Filesystem** | `core` | `file_explorer`, `read_file`, `file_editor` |
468
478
  | **Search** | `core` | `search_codebase`, `get_project_structure` |
469
- | **Shell** | `core` | `run_shell_command` |
470
- | **Memory** | `metadata` | `save_memory`, `load_memory` |
471
- | **Notes** | `metadata` | `create_note` |
472
- | **Tasks** | `metadata` | `list_tasks`, `show_task` |
473
- | **Python Editor** | `python` | `python_editor` (CST-based structural editing) |
474
- | **Background Processes** | `background` | `run_background_process`, `get_background_output`, `kill_background_process`, `list_background_processes` |
475
- | **Virtual Environments** | `venv` | `create_virtualenv`, `install_requirements`, `list_virtualenvs`, `activate_virtualenv`, `remove_virtualenv` |
479
+ | **Shell** | `core` | `bash` |
480
+ | **Session context** | `core` | `context` |
481
+ | **Skills** | `core` | `skill` |
482
+ | **Agents** | `core` | `agent` (registered when agents are configured) |
483
+ | **Notes** | `metadata` | `note` |
484
+ | **Tasks** | `metadata` | `task` |
485
+ | **Background Processes** | `background` | `background_process` |
476
486
  | **Web** | `http` | `fetch_web` |
477
- | **DBS** | `dbs` | `dbs_tool` (RAG API for DBS issues) |
478
487
  | **Environment** | `env` | `manage_environment_vars` |
479
- | **Temporal** | `temporal` | `temporal_workflow` |
480
488
 
481
489
  **Tag System:** Tools are filtered by tags. Default enabled tags: `["core", "metadata"]`. Use `/plugin` in TUI to toggle additional tags at runtime.
482
490
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ayder-cli
3
- Version: 2.5.1
3
+ Version: 2.5.3
4
4
  Summary: AI agent for any LLMs
5
5
  Project-URL: Homepage, https://github.com/ayder/ayder-cli
6
6
  Project-URL: Repository, https://github.com/ayder/ayder-cli.git
@@ -203,7 +203,7 @@ provider = "openai" # Active provider profile name
203
203
  editor = "vim" # Editor for /task-edit command
204
204
  verbose = false # Show file contents after write + LLM debug
205
205
  max_background_processes = 5 # Max concurrent background processes (1-20)
206
- max_iterations = 10 # Max agentic iterations per message (1-100)
206
+ max_iterations = 200 # LLM calls per message before the loop stops (0 = unlimited)
207
207
  max_output_tokens = 32768 # Max tokens in LLM response
208
208
  max_history_messages = 30 # Messages kept in history
209
209
  prompt = "STANDARD" # System prompt tier: MINIMAL, STANDARD, EXTENDED
@@ -535,6 +535,7 @@ inside the Ollama summary.
535
535
  | `Ctrl+L` | Clear chat |
536
536
  | `Ctrl+O` | Toggle tool panel |
537
537
  | `Ctrl+T` | Toggle thinking/reasoning blocks |
538
+ | `Shift` + drag | Select text with the mouse (Option in iTerm2 and Terminal.app) |
538
539
  | `PageUp` / `PageDown` | Scroll chat view |
539
540
  | `Tab` | Auto-complete slash commands |
540
541
 
@@ -586,7 +587,7 @@ ayder-cli includes a built-in task system:
586
587
 
587
588
  Tasks are stored as markdown files in `.ayder/tasks/` using slug-based filenames (e.g., `TASK-001-add-auth-middleware.md`).
588
589
 
589
- The `task` tool resolves identifiers (a path, filename, ID or slug) only to files inside `.ayder/tasks/`. An identifier that points elsewhere, including through a symlink, is not resolved. If `.ayder/tasks/`, `.ayder/context/` or `.ayder/notes/` itself resolves outside the project, those tools return a security error.
590
+ The `task` tool resolves identifiers (a path, filename, ID or slug) only to files inside `.ayder/tasks/`. An identifier that points elsewhere, including through a symlink, is not resolved. If `.ayder/tasks/`, `.ayder/context/` or `.ayder/notes/` itself resolves outside the project, those tools return a security error. An ID (`7`, `007`, `TASK-007`) matches only that task. A slug must match one task (an exact slug wins); if several match, the tool lists them and asks for the ID. `section` names a `##` heading; the `#` title is never a section.
590
591
 
591
592
  ```
592
593
  > /tasks # Interactive task browser
@@ -776,7 +777,8 @@ project root, then start Ayder:
776
777
  "local-tools": {
777
778
  "command": "python",
778
779
  "args": ["server.py"],
779
- "env": {"EXAMPLE_SETTING": "value"}
780
+ "env": {"EXAMPLE_SETTING": "value"},
781
+ "parallel": false
780
782
  },
781
783
  "remote-tools": {
782
784
  "url": "http://localhost:8000/mcp"
@@ -792,6 +794,16 @@ is needed. Tool calls retain the usual permissions: `x` for stdio servers and
792
794
  `http` for HTTP servers. Configure only servers you intend Ayder to connect to:
793
795
  local server commands start during runtime initialization to discover tools.
794
796
 
797
+ Calls to MCP tools in one response run at the same time by default. Set
798
+ `"parallel": false` on a server to run its calls one at a time, in the order the
799
+ model sent them. Do this for servers that write local files, so a read sent in
800
+ the same response cannot see the file before the write. `"parallel": true` runs
801
+ all of a server's tools concurrently, whatever the server declares. Without the
802
+ key, the server's own tool annotations decide: a tool marked `readOnlyHint`
803
+ runs concurrently, and one marked `readOnlyHint: false` or `destructiveHint`
804
+ runs alone. MCP calls always wait for built-in tools that change things
805
+ (`file_editor`, `bash`, ...) sent before them.
806
+
795
807
  Tools keep their server-provided names unless they conflict with an existing
796
808
  tool; conflicting names receive a `server__` prefix (and a numeric suffix if
797
809
  needed). Unreachable servers are skipped so other tools remain available.
@@ -160,7 +160,7 @@ provider = "openai" # Active provider profile name
160
160
  editor = "vim" # Editor for /task-edit command
161
161
  verbose = false # Show file contents after write + LLM debug
162
162
  max_background_processes = 5 # Max concurrent background processes (1-20)
163
- max_iterations = 10 # Max agentic iterations per message (1-100)
163
+ max_iterations = 200 # LLM calls per message before the loop stops (0 = unlimited)
164
164
  max_output_tokens = 32768 # Max tokens in LLM response
165
165
  max_history_messages = 30 # Messages kept in history
166
166
  prompt = "STANDARD" # System prompt tier: MINIMAL, STANDARD, EXTENDED
@@ -492,6 +492,7 @@ inside the Ollama summary.
492
492
  | `Ctrl+L` | Clear chat |
493
493
  | `Ctrl+O` | Toggle tool panel |
494
494
  | `Ctrl+T` | Toggle thinking/reasoning blocks |
495
+ | `Shift` + drag | Select text with the mouse (Option in iTerm2 and Terminal.app) |
495
496
  | `PageUp` / `PageDown` | Scroll chat view |
496
497
  | `Tab` | Auto-complete slash commands |
497
498
 
@@ -543,7 +544,7 @@ ayder-cli includes a built-in task system:
543
544
 
544
545
  Tasks are stored as markdown files in `.ayder/tasks/` using slug-based filenames (e.g., `TASK-001-add-auth-middleware.md`).
545
546
 
546
- The `task` tool resolves identifiers (a path, filename, ID or slug) only to files inside `.ayder/tasks/`. An identifier that points elsewhere, including through a symlink, is not resolved. If `.ayder/tasks/`, `.ayder/context/` or `.ayder/notes/` itself resolves outside the project, those tools return a security error.
547
+ The `task` tool resolves identifiers (a path, filename, ID or slug) only to files inside `.ayder/tasks/`. An identifier that points elsewhere, including through a symlink, is not resolved. If `.ayder/tasks/`, `.ayder/context/` or `.ayder/notes/` itself resolves outside the project, those tools return a security error. An ID (`7`, `007`, `TASK-007`) matches only that task. A slug must match one task (an exact slug wins); if several match, the tool lists them and asks for the ID. `section` names a `##` heading; the `#` title is never a section.
547
548
 
548
549
  ```
549
550
  > /tasks # Interactive task browser
@@ -733,7 +734,8 @@ project root, then start Ayder:
733
734
  "local-tools": {
734
735
  "command": "python",
735
736
  "args": ["server.py"],
736
- "env": {"EXAMPLE_SETTING": "value"}
737
+ "env": {"EXAMPLE_SETTING": "value"},
738
+ "parallel": false
737
739
  },
738
740
  "remote-tools": {
739
741
  "url": "http://localhost:8000/mcp"
@@ -749,6 +751,16 @@ is needed. Tool calls retain the usual permissions: `x` for stdio servers and
749
751
  `http` for HTTP servers. Configure only servers you intend Ayder to connect to:
750
752
  local server commands start during runtime initialization to discover tools.
751
753
 
754
+ Calls to MCP tools in one response run at the same time by default. Set
755
+ `"parallel": false` on a server to run its calls one at a time, in the order the
756
+ model sent them. Do this for servers that write local files, so a read sent in
757
+ the same response cannot see the file before the write. `"parallel": true` runs
758
+ all of a server's tools concurrently, whatever the server declares. Without the
759
+ key, the server's own tool annotations decide: a tool marked `readOnlyHint`
760
+ runs concurrently, and one marked `readOnlyHint: false` or `destructiveHint`
761
+ runs alone. MCP calls always wait for built-in tools that change things
762
+ (`file_editor`, `bash`, ...) sent before them.
763
+
752
764
  Tools keep their server-provided names unless they conflict with an existing
753
765
  tool; conflicting names receive a `server__` prefix (and a numeric suffix if
754
766
  needed). Unreachable servers are skipped so other tools remain available.
@@ -12,7 +12,7 @@ Input: the candidate SHA.
12
12
  gates and the test suite, and stops at the first failing task.
13
13
  4. Copy the final pytest summary line (`=== N passed, M skipped in …s ===`) verbatim.
14
14
 
15
- Last measured: `2743 passed, 2 skipped` on `fix/session-environment-prompt` (2026-10-19, 2.5.1).
15
+ Last measured: `3026 passed, 2 skipped` on `feat/tui-tweaks` (2026-11-13, release 2.5.3).
16
16
 
17
17
  ## Report format
18
18
 
@@ -97,10 +97,10 @@ ayder-cli is an AI agent chat client with a modular, layered architecture:
97
97
  1. **Layered Architecture**: Clear separation between entry → app → service → core → tools
98
98
  2. **Protocol-Based**: `ChatCallbacks` protocol decouples the chat loop from UI concerns; `InteractionSink` decouples LLM providers from UI for debug events
99
99
  3. **Single Composition Root**: `application/runtime_factory.create_runtime()` assembles all dependencies — no duplicated wiring between CLI and TUI
100
- 4. **Single Loop**: `ChatLoop` (in `loops/chat_loop.py`) owns the full async LLM + tool execution loop; both CLI and TUI route through it
100
+ 4. **Single Loop**: `ChatLoop` (in `loops/chat_loop.py`) owns the full async LLM + tool execution loop; both CLI and TUI route through it. A run ends on a text-only reply, a cancel, an error, `max_iterations` LLM calls (`[app]` 200, agents 100), or 3 reasoning-only replies in a row; from the 3rd identical tool call in a row, the result carries a `[harness]` note
101
101
  5. **Single Execution Path**: `ExecutionPolicy.execute_with_registry()` is the sole tool execution entry point; validation → permission → execute, no inline policy in loop code
102
102
  6. **Single Validation Path**: `ValidationAuthority → SchemaValidator` is the only validation stage; schema derived from live `TOOL_DEFINITIONS` registry (no hardcoded lists)
103
- 7. **Sandboxed Paths**: All file operations go through `ProjectContext` for security (project root plus the session scratch directory from `new_scratch_dir`)
103
+ 7. **Sandboxed Paths**: All file operations go through `ProjectContext` for security (project root plus the session scratch directory from `new_scratch_dir`). Only a path outside the sandbox (`PathOutsideSandboxError`) is reported as a security error; other bad input, such as a binary file or a non-numeric line number, is a validation error
104
104
  8. **Single Execution Engine**: Both TUI and CLI drive `ChatLoop.run()` through the `ChatCallbacks` protocol (`AppCallbacks` and `CliCallbacks` respectively); CLI runs it via `asyncio.run`
105
105
 
106
106
  ---
@@ -293,7 +293,7 @@ the design rationale.
293
293
  | `tools/plugin_github.py` | GitHub-sourced plugin fetcher | remote-plugin loader |
294
294
  | `tools/builtins/filesystem.py` | File system tool impls | `file_explorer()`, `read_file()`, `file_editor()` |
295
295
  | `tools/builtins/search.py` | Search tool impls | `search_codebase()`, `get_project_structure()` |
296
- | `tools/builtins/shell.py` | Shell execution impl | `bash()` |
296
+ | `tools/builtins/shell.py` | Shell execution impl: own session, closed stdin, prompts/pagers off (`GIT_TERMINAL_PROMPT=0`, `PAGER`/`GIT_PAGER=cat`; `environment` overrides), process-group kill on timeout with partial output, per-stream output bounds | `bash()` |
297
297
  | `tools/builtins/context.py` | Session context snapshots | `context` |
298
298
  | `tools/builtins/notes.py` | Note-taking tool | `create_note()` |
299
299
  | `tools/builtins/tasks.py` | Task-management tools | `list_tasks()`, `show_task()` |
@@ -306,7 +306,7 @@ the design rationale.
306
306
 
307
307
  | Module | Purpose | Key Classes/Functions |
308
308
  |--------|---------|----------------------|
309
- | `process_manager.py` | Background processes | `ProcessManager`, `background_process()` |
309
+ | `process_manager.py` | Background processes (closed stdin; `stop` and exit cleanup kill the whole process group, also after the leader exited) | `ProcessManager`, `background_process()` |
310
310
  | `prompts.py` | System prompts | `SYSTEM_PROMPT`, `PLANNING_PROMPT_TEMPLATE`, `get_system_prompt()` |
311
311
  | `parser.py` | XML tool-call parsing | `parse_custom_tool_calls()` |
312
312
 
@@ -329,11 +329,13 @@ AyderApp (Textual App)
329
329
  ├── CSS (from theme_manager.py)
330
330
  ├── Compose:
331
331
  │ ├── Banner (Static)
332
+ │ ├── ToolPanel (custom widget) ← Tool calls; hidden until Ctrl+O, opens at the top (fixed 10% height)
333
+ │ ├── ThinkingPanel (custom widget) ← Reasoning stream; Ctrl+T, opens at the top (fixed 30% height)
334
+ │ ├── AgentPanel (custom widget) ← Agent runs; Ctrl+G, opens at the top (fixed 10% height)
332
335
  │ ├── ChatView (custom widget) ← Messages displayed here
333
- │ ├── ToolPanel (custom widget) ← Tool calls shown here
334
336
  │ ├── ActivityBar (custom widget) ← Status indicators
335
337
  │ ├── CLIInputBar (custom widget) ← User input
336
- │ └── StatusBar (custom widget) ← Model, tokens, iterations
338
+ │ └── StatusBar (custom widget) ← Working directory (~ for home, shortened from the left), model, effort, mode, context usage, files
337
339
  │
338
340
  ├── Screens (Modal):
339
341
  │ ├── CLIConfirmScreen ← Tool confirmation with diff
@@ -574,15 +576,15 @@ The TUI module provides a clean, terminal-like interface with:
574
576
  - Simple text output with prefixes
575
577
  - Minimal borders and chrome design
576
578
  - Slash command auto-completion
577
- - Status bar with contextual information
578
- - Mouse-free operation optimized for keyboard
579
+ - Status bar with contextual information, starting with the working directory (home shown as `~`; a long path is shortened from the left to at most a third of the bar, never below `…/<last component>`, regardless of the other items, which may overflow the bar's right edge)
580
+ - Keyboard-first operation, with mouse support enabled
579
581
 
580
582
  It exposes key components like AyderApp, widgets (ChatView, ToolPanel), and screens (CLIConfirmScreen) for building the terminal interface.
581
583
 
582
584
  ### TUI Application File Summary (src/ayder_cli/tui/app.py)
583
585
 
584
586
  AyderApp is the main Textual application implementing a chat-style interface:
585
- - **Layout**: Banner, ChatView, ToolPanel, ActivityBar, CLIInputBar, StatusBar
587
+ - **Layout**: ToolPanel, ThinkingPanel and AgentPanel (hidden by default; they open at the top, above the chat, at a fixed 10% / 30% / 10% of the screen height with their content scrolling inside, and toggling prints no chat message), ChatView, ActivityBar, CLIInputBar, StatusBar
586
588
  - **Keybindings**: Ctrl+Q (quit), Ctrl+C/X (cancel), Ctrl+L (clear), Ctrl+O (toggle tools)
587
589
  - **Features**:
588
590
  - Async processing with worker threads
@@ -594,7 +596,7 @@ AyderApp is the main Textual application implementing a chat-style interface:
594
596
  The application manages:
595
597
  - LLM provider setup and configuration
596
598
  - Tool registry initialization with middleware
597
- - System prompt construction (base prompt + environment section + tool prompts + skill catalog; no project tree). The environment section (`prompts.build_environment_prompt`) gives the absolute working directory and the session start date and time (ISO 8601, local time with UTC offset). It is built once per session and reused on `/model` rebuilds.
599
+ - System prompt construction (base prompt + environment section + tool prompts + skill catalog; no project tree). The environment section (`prompts.build_environment_prompt`) gives the absolute working directory and the session start date and time (ISO 8601, local time with UTC offset). It also tells the model that replies render as Markdown (paragraphs separated by a blank line, no fixed-width wrapping). It is built once per session and reused on `/model` rebuilds. A resumed session (`--resume`) restores the provider it last used (the session file stores it; a provider no longer configured falls back to the default with a warning) and its `--system-prompt` text, keeps its history, and rebuilds the system prompt for the current session, so the scratch directory, start time, tool prompts and agent capability prompts are current; `/model` rebuilds keep the capability prompts.
598
600
  - Process manager for background operations
599
601
 
600
602
  ### Chat Loop Summary (src/ayder_cli/loops/chat_loop.py)
@@ -609,7 +611,7 @@ previously-split `AgentLoopBase` and `LoopConfig` were merged back in):
609
611
  - Routes *every* LLM response through the injected `ContextManagerProtocol` (`prepare_messages()` / `update_from_response()`); tool outputs are truncated at insertion time via `truncate_tool_result()` so the KV-cache prefix remains stable
610
612
 
611
613
  Key features:
612
- - Auto-approved tools run in parallel (`asyncio.as_completed`); confirmation-required tools run sequentially
614
+ - Tool calls run in emission order. Consecutive calls that are parallel-safe (`ToolDefinition.parallel_safe`, default False) and auto-approved run concurrently (`asyncio.as_completed`). Every other call runs alone, after confirmation if required. Once the user answers a confirmation with instructions, no later call in the batch runs. MCP tools default to parallel-safe; `.ayder/mcp.json` `"parallel"` and the tools' annotations override that
613
615
  - Confirmation gate applies to **both** OpenAI-format and XML/JSON custom tool calls
614
616
  - `ExecutionPolicy.execute_with_registry()` is the single execution entry (object check → `canonicalize_arguments()` → validate → permission → execute). Canonicalization applies aliases and `"123"`/`"true"`/`"false"` coercion; the loop's required-argument gate uses the same function
615
617
  - Argument integrity: `_parse_tool_arguments()` reports `ok`, `repaired` or `invalid`. Non-object arguments never run. Arguments repaired after being cut off (output token limit) run only for tools registered explicitly as `r`; other tools get an error asking the model to resend in smaller calls
@@ -645,6 +647,7 @@ Schema-driven tool definitions with auto-discovery:
645
647
  - **Required-tool validation**: Raises `ImportError` if core tools (`file_explorer`, `read_file`, `file_editor`, `bash`) are absent
646
648
  - **Permissions**: `"r"` (read), `"w"` (write), `"x"` (execute), `"http"` (network)
647
649
  - **Safety flags**: `safe_mode_blocked`, `is_terminal` per definition
650
+ - **Scheduling**: `parallel_safe` per definition: a bool, or a predicate over the call's arguments (`parallel_safe_when("action", ...)`); unknown tools are never parallel-safe
648
651
  - **Path parameters**: Names listed in `path_parameters` are automatically resolved via `ProjectContext`
649
652
  - **Aliases**: `parameter_aliases` tuples for common name normalisation
650
653
  - **Schema generation**: `to_openai_schema()` returns the OpenAI function-calling dict
@@ -92,6 +92,8 @@ max_output_tokens = 8192 # orchestrator response cap
92
92
  # window on a large-context model and wastes most of it. Set a finite number
93
93
  # only if you want a hard message cap regardless of window size.
94
94
  max_history_messages = 0
95
+ # LLM calls per user message before the loop stops and asks for input. 0 = unlimited.
96
+ max_iterations = 200
95
97
  agent_timeout = 1800 # seconds before a background agent is cancelled (30 min; reasoning+coding can be slow)
96
98
  # Tools the agents inherit. A coding harness needs file/shell/search (core),
97
99
  # tasks/notes (metadata), background process control for test suites
@@ -232,6 +234,7 @@ model = "glm-5.2:cloud"
232
234
  # skills = ["development-workflow"] # wins over the provider profile's skills; [app] is never read
233
235
  temperature = 0.4
234
236
  max_output_tokens = 8192
237
+ # max_iterations = 100 # LLM calls per run (default 100; 0 = unlimited)
235
238
  reasoning_effort = "high"
236
239
  system_prompt = """
237
240
  You are Project Manager #1 — the requirements analyst and spec author.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "ayder-cli"
7
- version = "2.5.1"
7
+ version = "2.5.3"
8
8
  description = "AI agent for any LLMs"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -31,6 +31,8 @@ class AgentConfig(BaseModel):
31
31
  num_ctx: int | None = None
32
32
  temperature: float | None = None
33
33
  max_output_tokens: int | None = None
34
+ # LLM calls per run before the loop stops; None = 100, 0 = unlimited.
35
+ max_iterations: int | None = None
34
36
  think: ThinkOption = None
35
37
  reasoning_effort: ReasoningEffort = None
36
38
  # None: the provider profile's setting; "none" or a list: see Config.skills.
@@ -57,7 +59,7 @@ class AgentConfig(BaseModel):
57
59
  new_data[key] = float(val)
58
60
  except ValueError:
59
61
  pass
60
- for key in ("num_ctx", "max_output_tokens"):
62
+ for key in ("num_ctx", "max_output_tokens", "max_iterations"):
61
63
  val = new_data.get(key)
62
64
  if isinstance(val, str) and val.strip():
63
65
  try:
@@ -27,6 +27,9 @@ logger = get_logger("agent")
27
27
  _ECHO_LINE = re.compile(r"^\s*(task_id|task_preview)\s*:", re.IGNORECASE)
28
28
  _VERDICT_LINE = re.compile(r"^\s*VERDICT\s*:", re.IGNORECASE)
29
29
 
30
+ # An agent's LLM calls per run when its [agents.<name>] sets no max_iterations.
31
+ AGENT_MAX_ITERATIONS = 100
32
+
30
33
 
31
34
  @dataclass
32
35
  class AgentRunOutcome:
@@ -157,6 +160,11 @@ class AgentRunner:
157
160
  permissions=self._permissions,
158
161
  tool_tags=frozenset(rt.config.tool_tags) if getattr(rt.config, "tool_tags", None) else None,
159
162
  max_history=getattr(rt.config, "max_history_messages", 30),
163
+ max_iterations=(
164
+ AGENT_MAX_ITERATIONS
165
+ if self._agent_config.max_iterations is None
166
+ else self._agent_config.max_iterations
167
+ ),
160
168
  session_id=self._session_id,
161
169
  run_id=self.run_id,
162
170
  )
@@ -11,7 +11,7 @@ import asyncio
11
11
  import json
12
12
  from typing import TYPE_CHECKING, Callable
13
13
 
14
- from ayder_cli.tools.definition import ToolDefinition
14
+ from ayder_cli.tools.definition import ToolDefinition, parallel_safe_when
15
15
 
16
16
  if TYPE_CHECKING:
17
17
  from ayder_cli.agents.registry import AgentRegistry
@@ -95,6 +95,7 @@ AGENT_TOOL_DEFINITION = ToolDefinition(
95
95
  "required": ["action"],
96
96
  },
97
97
  permission="r",
98
+ parallel_safe=parallel_safe_when("action", "list", "status", "read_result"),
98
99
  tags=("core", "agents"),
99
100
  max_result_chars=0,
100
101
  system_prompt="",
@@ -402,7 +402,8 @@ def main():
402
402
 
403
403
  # --resume: restore a saved session and launch the TUI. It is mutually
404
404
  # exclusive with session-shaping options — the saved file already carries
405
- # the model, permissions, agent mode, and system prompt.
405
+ # the provider, model, permissions, agent mode, and any --system-prompt text; the
406
+ # app rebuilds the rest of the system prompt for this session.
406
407
  if getattr(args, "resume", None):
407
408
  _conflicts: list[str] = []
408
409
  if getattr(args, "agent", False):
@@ -447,13 +448,25 @@ def main():
447
448
  print(f"Error: {e}", file=sys.stderr)
448
449
  sys.exit(1)
449
450
 
451
+ from ayder_cli.core.config import list_provider_profiles
450
452
  from ayder_cli.tui import run_tui
451
453
 
454
+ provider = sess.provider
455
+ if provider and provider not in list_provider_profiles():
456
+ print(
457
+ f"Warning: provider '{provider}' from the saved session is not "
458
+ "configured; using the default provider.",
459
+ file=sys.stderr,
460
+ )
461
+ provider = None
462
+
452
463
  run_tui(
453
464
  model=sess.model or "default",
465
+ provider=provider,
454
466
  safe_mode=sess.safe_mode,
455
467
  permissions=set(sess.permissions),
456
468
  agent_mode=sess.agent_mode,
469
+ system_prompt_override=sess.system_prompt_override,
457
470
  initial_messages=sess.messages,
458
471
  resume_session_id=sess.session_id,
459
472
  session_name=getattr(args, "name", None),
@@ -97,6 +97,7 @@ def _run_loop(
97
97
  permissions=set(permissions or {"r"}),
98
98
  tool_tags=frozenset(rt.config.tool_tags) if rt.config.tool_tags else None,
99
99
  max_history=rt.config.max_history_messages,
100
+ max_iterations=rt.config.max_iterations,
100
101
  session_id=session_id,
101
102
  )
102
103