ayder-cli 2.5.0__tar.gz → 2.5.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.
Files changed (360) hide show
  1. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/.github/workflows/python-package.yml +3 -0
  2. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/AGENTS.md +92 -84
  3. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/PKG-INFO +23 -10
  4. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/README.md +22 -9
  5. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/docs/GATE.md +1 -1
  6. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/docs/PROJECT_STRUCTURE.md +7 -6
  7. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/docs/config.toml.example +5 -2
  8. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/pyproject.toml +1 -1
  9. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/agents/config.py +3 -1
  10. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/agents/registry.py +3 -1
  11. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/agents/runner.py +8 -0
  12. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/agents/tool.py +2 -1
  13. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/application/runtime_factory.py +26 -3
  14. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/cli.py +14 -1
  15. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/cli_runner.py +1 -0
  16. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/core/config.py +9 -0
  17. ayder_cli-2.5.2/src/ayder_cli/core/context.py +158 -0
  18. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/core/session.py +12 -0
  19. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/core/skills.py +8 -6
  20. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/loops/chat_loop.py +152 -46
  21. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/process_manager.py +77 -48
  22. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/prompts.py +54 -0
  23. ayder_cli-2.5.2/src/ayder_cli/skills/development-workflow/SKILL.md +27 -0
  24. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/context.py +4 -2
  25. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/context_definitions.py +2 -1
  26. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/filesystem.py +99 -21
  27. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/filesystem_definitions.py +12 -6
  28. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/note_tool.py +4 -2
  29. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/notes.py +4 -2
  30. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/notes_definitions.py +2 -1
  31. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/process_manager_definitions.py +2 -1
  32. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/search.py +4 -2
  33. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/search_definitions.py +2 -0
  34. ayder_cli-2.5.2/src/ayder_cli/tools/builtins/shell.py +146 -0
  35. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/shell_definitions.py +5 -1
  36. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/skill.py +18 -4
  37. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/skill_definitions.py +3 -1
  38. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/task_definitions.py +14 -6
  39. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/task_tool.py +158 -40
  40. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/tasks.py +44 -12
  41. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/utils_tools.py +4 -2
  42. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/web_definitions.py +2 -1
  43. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/definition.py +56 -2
  44. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/execution.py +4 -2
  45. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/mcp.py +28 -4
  46. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tui/__init__.py +7 -1
  47. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tui/app.py +20 -4
  48. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/agents/test_worktree_isolation.py +27 -0
  49. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/application/test_runtime_factory.py +4 -0
  50. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/conftest.py +9 -0
  51. ayder_cli-2.5.2/tests/core/test_scratch_dir.py +115 -0
  52. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_session.py +32 -0
  53. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_skills.py +4 -1
  54. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_skills_builtin_sync.py +4 -4
  55. ayder_cli-2.5.2/tests/loops/test_chat_loop_guards.py +282 -0
  56. ayder_cli-2.5.2/tests/loops/test_tool_batch_ordering.py +254 -0
  57. ayder_cli-2.5.2/tests/test_agents_md.py +114 -0
  58. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/test_cli.py +55 -0
  59. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/test_process_manager.py +2 -2
  60. ayder_cli-2.5.2/tests/test_prompts_environment.py +102 -0
  61. ayder_cli-2.5.2/tests/tools/test_bash_process_safety.py +198 -0
  62. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_bash_tool.py +34 -23
  63. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_definition_discovery.py +39 -0
  64. ayder_cli-2.5.2/tests/tools/test_error_labels.py +103 -0
  65. ayder_cli-2.5.2/tests/tools/test_file_tool_output.py +182 -0
  66. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_impl.py +2 -2
  67. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_impl_coverage.py +5 -3
  68. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_mcp.py +21 -1
  69. ayder_cli-2.5.2/tests/tools/test_parallel_safe.py +91 -0
  70. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_path_security.py +2 -2
  71. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_skill_tool.py +44 -1
  72. ayder_cli-2.5.2/tests/tools/test_task_integrity.py +193 -0
  73. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_task_tool.py +114 -3
  74. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_utils.py +3 -3
  75. ayder_cli-2.5.2/tests/tui/test_resume.py +162 -0
  76. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/ui/test_confirm_screen.py +2 -0
  77. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/ui/test_tui_system_prompt_no_structure.py +10 -0
  78. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/uv.lock +2 -2
  79. ayder_cli-2.5.0/docs/superpowers/plans/2026-06-26-file-editor-improvements.md +0 -771
  80. ayder_cli-2.5.0/docs/superpowers/plans/2026-06-26-session-save-resume.md +0 -1047
  81. ayder_cli-2.5.0/docs/superpowers/specs/2026-06-26-file-editor-improvements-design.md +0 -180
  82. ayder_cli-2.5.0/docs/superpowers/specs/2026-06-26-session-save-resume-design.md +0 -319
  83. ayder_cli-2.5.0/src/ayder_cli/core/context.py +0 -92
  84. ayder_cli-2.5.0/src/ayder_cli/skills/engineering/SKILL.md +0 -35
  85. ayder_cli-2.5.0/src/ayder_cli/tools/builtins/shell.py +0 -109
  86. ayder_cli-2.5.0/tests/tui/test_resume.py +0 -86
  87. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/.github/workflows/ci.yml +0 -0
  88. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/.gitignore +0 -0
  89. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/.python-version +0 -0
  90. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/LICENSE +0 -0
  91. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/docs/README_AGENT_WORKFLOW.md +0 -0
  92. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/docs/README_OLLAMA.md +0 -0
  93. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/docs/cc.png +0 -0
  94. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/scripts/check_exception_handlers.py +0 -0
  95. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/scripts/check_log_arguments.py +0 -0
  96. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/scripts/check_logging_imports.py +0 -0
  97. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/scripts/exception_baseline.txt +0 -0
  98. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/scripts/find_percent_logging.py +0 -0
  99. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/scripts/log_argument_baseline.txt +0 -0
  100. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/scripts/logging_gates.py +0 -0
  101. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/__init__.py +0 -0
  102. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/__main__.py +0 -0
  103. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/agents/__init__.py +0 -0
  104. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/agents/callbacks.py +0 -0
  105. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/agents/run.py +0 -0
  106. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/agents/worktree.py +0 -0
  107. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/application/README.md +0 -0
  108. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/application/__init__.py +0 -0
  109. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/application/execution_policy.py +0 -0
  110. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/application/message_contract.py +0 -0
  111. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/application/validation.py +0 -0
  112. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/cli_callbacks.py +0 -0
  113. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/console.py +0 -0
  114. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/core/cache_monitor.py +0 -0
  115. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/core/config_migration.py +0 -0
  116. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/core/context_manager.py +0 -0
  117. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/core/context_manager_factory.py +0 -0
  118. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/core/default_context_manager.py +0 -0
  119. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/core/ollama_context_manager.py +0 -0
  120. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/core/reasoning.py +0 -0
  121. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/core/result.py +0 -0
  122. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/diagnostics.py +0 -0
  123. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/log.py +0 -0
  124. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/logging_config.py +0 -0
  125. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/loops/__init__.py +0 -0
  126. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/masking.py +0 -0
  127. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/parser.py +0 -0
  128. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/providers/__init__.py +0 -0
  129. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/providers/base.py +0 -0
  130. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/providers/evren.py +0 -0
  131. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/claude.py +0 -0
  132. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/deepseek.py +0 -0
  133. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/gemini.py +0 -0
  134. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/glm.py +0 -0
  135. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama.py +0 -0
  136. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama_drivers/__init__.py +0 -0
  137. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama_drivers/_errors.py +0 -0
  138. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama_drivers/base.py +0 -0
  139. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama_drivers/deepseek.py +0 -0
  140. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama_drivers/generic_native.py +0 -0
  141. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama_drivers/generic_xml.py +0 -0
  142. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama_drivers/matrix.py +0 -0
  143. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama_drivers/minimax.py +0 -0
  144. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama_drivers/qwen3.py +0 -0
  145. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama_drivers/registry.py +0 -0
  146. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama_inspector.py +0 -0
  147. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/openai.py +0 -0
  148. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/qwen.py +0 -0
  149. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/providers/orchestrator.py +0 -0
  150. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/providers/retry.py +0 -0
  151. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/services/__init__.py +0 -0
  152. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/services/interactions.py +0 -0
  153. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/services/messaging_inbox.py +0 -0
  154. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/themes/__init__.py +0 -0
  155. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/themes/ayder.py +0 -0
  156. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/themes/claude.py +0 -0
  157. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/__init__.py +0 -0
  158. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/__init__.py +0 -0
  159. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/background_process_tool.py +0 -0
  160. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/utils_tools_definitions.py +0 -0
  161. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/web.py +0 -0
  162. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/hooks.py +0 -0
  163. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/mcp_client.py +0 -0
  164. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/normalization.py +0 -0
  165. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/plugin_api.py +0 -0
  166. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/plugin_github.py +0 -0
  167. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/plugin_manager.py +0 -0
  168. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/plugin_status.py +0 -0
  169. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/registry.py +0 -0
  170. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/schemas.py +0 -0
  171. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tools/utils.py +0 -0
  172. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tui/adapter.py +0 -0
  173. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tui/commands.py +0 -0
  174. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tui/helpers.py +0 -0
  175. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tui/keybindings.py +0 -0
  176. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tui/parser.py +0 -0
  177. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tui/rendering.py +0 -0
  178. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tui/screens.py +0 -0
  179. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tui/theme_manager.py +0 -0
  180. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tui/types.py +0 -0
  181. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/tui/widgets.py +0 -0
  182. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/ui.py +0 -0
  183. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/src/ayder_cli/version.py +0 -0
  184. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/COVERAGE.md +0 -0
  185. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/__init__.py +0 -0
  186. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/agents/__init__.py +0 -0
  187. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/agents/test_agent_consolidated.py +0 -0
  188. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/agents/test_agent_severity.py +0 -0
  189. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/agents/test_agent_tools.py +0 -0
  190. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/agents/test_callbacks.py +0 -0
  191. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/agents/test_config.py +0 -0
  192. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/agents/test_integration.py +0 -0
  193. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/agents/test_queue.py +0 -0
  194. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/agents/test_registry.py +0 -0
  195. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/agents/test_run.py +0 -0
  196. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/agents/test_runner.py +0 -0
  197. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/agents/test_runner_provider_unavailable.py +0 -0
  198. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/agents/test_tool.py +0 -0
  199. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/agents/test_worktree_helpers.py +0 -0
  200. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/application/test_argument_canonicalization.py +0 -0
  201. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/application/test_execution_result_truthfulness.py +0 -0
  202. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/application/test_message_contract.py +0 -0
  203. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/client/test_main.py +0 -0
  204. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/convergence/__init__.py +0 -0
  205. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/convergence/test_execution_policy_parity.py +0 -0
  206. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/convergence/test_runtime_wiring.py +0 -0
  207. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/convergence/test_validation_path.py +0 -0
  208. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_asyncio_bridge.py +0 -0
  209. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_cache_monitor.py +0 -0
  210. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_config.py +0 -0
  211. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_config_coverage.py +0 -0
  212. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_config_migration.py +0 -0
  213. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_config_provider_logging.py +0 -0
  214. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_config_retry.py +0 -0
  215. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_config_skills.py +0 -0
  216. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_config_v2.py +0 -0
  217. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_context_manager_factory.py +0 -0
  218. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_default_config_evren.py +0 -0
  219. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_default_context_manager.py +0 -0
  220. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_default_context_manager_should_compact.py +0 -0
  221. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_default_context_newest_unit.py +0 -0
  222. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_default_context_skill_resupply.py +0 -0
  223. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_event_emission.py +0 -0
  224. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_event_stream.py +0 -0
  225. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_exception_guarantee.py +0 -0
  226. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_exception_hooks.py +0 -0
  227. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_log_facade.py +0 -0
  228. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_logging_config_keys.py +0 -0
  229. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_logging_sinks.py +0 -0
  230. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_loguru_caplog.py +0 -0
  231. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_max_output_tokens_default.py +0 -0
  232. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_ollama_compaction_persistence.py +0 -0
  233. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_ollama_context_manager.py +0 -0
  234. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_ollama_context_manager_cache_monitor.py +0 -0
  235. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_ollama_context_manager_max_history.py +0 -0
  236. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_ollama_skill_resupply.py +0 -0
  237. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_parameter_aliasing.py +0 -0
  238. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_parser.py +0 -0
  239. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_reasoning_config.py +0 -0
  240. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_session_id_threading.py +0 -0
  241. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/core/test_sink_masking.py +0 -0
  242. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/loops/__init__.py +0 -0
  243. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/loops/test_base.py +0 -0
  244. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/loops/test_chat_loop_hook.py +0 -0
  245. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/loops/test_chat_loop_tool_truncation.py +0 -0
  246. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/loops/test_loop_severity.py +0 -0
  247. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/loops/test_required_args_aliases.py +0 -0
  248. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/loops/test_tool_argument_integrity.py +0 -0
  249. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/loops/test_tool_batch_cancellation.py +0 -0
  250. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/__init__.py +0 -0
  251. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/__init__.py +0 -0
  252. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/test_base.py +0 -0
  253. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/test_deepseek.py +0 -0
  254. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/test_errors.py +0 -0
  255. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/test_fallback.py +0 -0
  256. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/test_generic_native.py +0 -0
  257. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/test_generic_xml.py +0 -0
  258. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/test_matrix.py +0 -0
  259. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/test_minimax.py +0 -0
  260. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/test_provider_integration.py +0 -0
  261. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/test_qwen3.py +0 -0
  262. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/test_registry.py +0 -0
  263. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/test_claude_stream_tool_calls.py +0 -0
  264. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/test_evren.py +0 -0
  265. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/test_gemini_function_calls.py +0 -0
  266. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/test_glm_async.py +0 -0
  267. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/test_ollama_inspector.py +0 -0
  268. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/test_ollama_native.py +0 -0
  269. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/test_ollama_parallel_tool_call_ids.py +0 -0
  270. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/test_ollama_xml.py +0 -0
  271. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/test_ollama_xml_autoroute.py +0 -0
  272. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/test_ollama_xml_usage.py +0 -0
  273. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/test_openai_list_models.py +0 -0
  274. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/test_orchestrator_capabilities.py +0 -0
  275. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/test_provider_channel_binding.py +0 -0
  276. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/test_provider_severity.py +0 -0
  277. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/test_qwen_async.py +0 -0
  278. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/test_reasoning_effort.py +0 -0
  279. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/test_retry_classifier.py +0 -0
  280. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/test_retry_integration.py +0 -0
  281. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/test_retrying_provider.py +0 -0
  282. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/providers/test_skill_load_prefix.py +0 -0
  283. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/scripts/test_exception_gate.py +0 -0
  284. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/scripts/test_log_argument_gate.py +0 -0
  285. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/scripts/test_logging_policy_gates.py +0 -0
  286. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/scripts/test_loguru_private_shape.py +0 -0
  287. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/services/test_boundary.py +0 -0
  288. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/services/test_interaction_sink.py +0 -0
  289. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/services/test_messaging_inbox.py +0 -0
  290. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/test_cli_callbacks.py +0 -0
  291. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/test_context.py +0 -0
  292. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/test_env_manager.py +0 -0
  293. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/test_logging_config.py +0 -0
  294. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/test_notes.py +0 -0
  295. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/test_prompts_general.py +0 -0
  296. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/test_tasks.py +0 -0
  297. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/__init__.py +0 -0
  298. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_agent_notes.py +0 -0
  299. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_background_process_tool.py +0 -0
  300. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_context_storage_confinement.py +0 -0
  301. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_di_injection.py +0 -0
  302. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_file_editor_hardening.py +0 -0
  303. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_file_editor_size_limit.py +0 -0
  304. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_mcp_client.py +0 -0
  305. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_note_tool.py +0 -0
  306. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_notes_api.py +0 -0
  307. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_notes_confinement.py +0 -0
  308. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_plugin_api.py +0 -0
  309. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_plugin_github.py +0 -0
  310. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_plugin_loading.py +0 -0
  311. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_plugin_manager.py +0 -0
  312. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_plugin_status.py +0 -0
  313. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_registry.py +0 -0
  314. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_registry_coverage.py +0 -0
  315. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_result.py +0 -0
  316. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_schemas.py +0 -0
  317. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_search_codebase.py +0 -0
  318. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_search_hardening.py +0 -0
  319. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_skill_catalog_and_filter.py +0 -0
  320. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_skill_scope_wiring.py +0 -0
  321. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_task_path_confinement.py +0 -0
  322. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_tool_severity.py +0 -0
  323. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_unexpected_args.py +0 -0
  324. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tools/test_web.py +0 -0
  325. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tui/__init__.py +0 -0
  326. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tui/test_agent_list_screen.py +0 -0
  327. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tui/test_do_clear_coordination.py +0 -0
  328. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tui/test_evren_terms.py +0 -0
  329. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tui/test_follow_mode.py +0 -0
  330. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tui/test_help_screen.py +0 -0
  331. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tui/test_input_box.py +0 -0
  332. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tui/test_keybindings.py +0 -0
  333. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tui/test_multi_select_screen.py +0 -0
  334. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tui/test_multiline_input.py +0 -0
  335. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tui/test_paste.py +0 -0
  336. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tui/test_peer_message_turn.py +0 -0
  337. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tui/test_pending_compact_consumer.py +0 -0
  338. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tui/test_pull_delivery.py +0 -0
  339. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tui/test_status_bar_badges.py +0 -0
  340. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tui/test_themes.py +0 -0
  341. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tui/test_turn_consumer.py +0 -0
  342. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/tui/test_widgets.py +0 -0
  343. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/ui/test_diff_preview.py +0 -0
  344. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/ui/test_plugin_autoenable.py +0 -0
  345. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/ui/test_provider_switch.py +0 -0
  346. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/ui/test_run_tui_startup.py +0 -0
  347. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/ui/test_tui_assistant_sanitization.py +0 -0
  348. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/ui/test_tui_chat_loop.py +0 -0
  349. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/ui/test_tui_commands_agent.py +0 -0
  350. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/ui/test_tui_commands_effort.py +0 -0
  351. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/ui/test_tui_commands_logging.py +0 -0
  352. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/ui/test_tui_commands_plugin.py +0 -0
  353. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/ui/test_tui_commands_provider.py +0 -0
  354. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/ui/test_tui_commands_skill.py +0 -0
  355. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/ui/test_tui_helpers.py +0 -0
  356. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/ui/test_tui_temporal_command.py +0 -0
  357. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/ui/test_tui_widgets.py +0 -0
  358. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/ui/test_ui.py +0 -0
  359. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/ui/test_ui_coverage.py +0 -0
  360. {ayder_cli-2.5.0 → ayder_cli-2.5.2}/tests/ui/test_ui_verbose.py +0 -0
@@ -11,6 +11,9 @@ on:
11
11
 
12
12
  jobs:
13
13
  build-and-publish:
14
+ # The pypi environment admits only main and release-*/beta-* tags, so on a
15
+ # pull request the job is refused before any step runs and the PR shows red.
16
+ if: github.event_name == 'push'
14
17
  runs-on: ubuntu-latest
15
18
  # This job only runs in the context of your 'pypi' environment
16
19
  environment: pypi
@@ -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.0
3
+ Version: 2.5.2
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
@@ -82,7 +82,7 @@ LLMs on their own can only generate text. To be a useful coding assistant, the m
82
82
 
83
83
  Each tool has an OpenAI-compatible JSON schema so models that support function calling can use them natively. For models that don't, ayder-cli also parses a custom XML-like syntax (`<function=name><parameter=key>value</parameter></function>`) as a fallback.
84
84
 
85
- - **Path sandboxing**: All file operations are confined to the project root via `ProjectContext`. Path traversal attacks (`../`) and absolute paths outside the project are blocked.
85
+ - **Path sandboxing**: All file operations are confined to the project root via `ProjectContext`. Path traversal attacks (`../`) and absolute paths outside the project are blocked. The one exception is the session scratch directory, `/tmp/ayder-<uid>/<project>-<hash>/<session>/` (mode 0700, one subdirectory per agent run), which the system prompt names as the place for temporary files and which the file tools accept. It is not cleaned up; the OS clears `/tmp`.
86
86
  - **Safe mode** (TUI): Blocks `file_editor`, `run_shell_command`, `run_background_process`, `kill_background_process`, and `fetch_web`.
87
87
  - Every tool call requires your confirmation before it runs -- you always stay in control. Use `-r`, `-w`, `-x` flags to auto-approve tool categories.
88
88
  - You may also prefer to run ayder-cli in a container for additional security.
@@ -203,12 +203,12 @@ 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
210
210
  tool_tags = ["core", "metadata"] # Enabled tool tags (see /plugin)
211
- # skills = ["engineering"] # or "none"; default: the built-in skills
211
+ # skills = ["development-workflow"] # or "none"; default: the built-in skills
212
212
  agent_timeout = 300 # Seconds before a background agent is cancelled
213
213
 
214
214
  [logging]
@@ -354,7 +354,8 @@ ayder -f instructions.txt
354
354
  ayder --stdin < prompt.txt
355
355
 
356
356
  # Override the main LLM system prompt with a file
357
- # (tool instructions are still appended)
357
+ # (the environment section with working directory and start time,
358
+ # and the tool instructions, are still appended)
358
359
  ayder --system-prompt prompt-file.md "refactor this code"
359
360
  ```
360
361
 
@@ -478,8 +479,9 @@ later one overrides an earlier one with the same name:
478
479
  2. your skills in `~/.ayder/skills/<name>/`
479
480
  3. project skills in `<project>/.ayder/skills/<name>/`
480
481
 
481
- ayder ships an `engineering` skill (build, change, debug or review code;
482
- research; plan multi-step work). The system prompt is a general assistant;
482
+ ayder ships a `development-workflow` skill for multi-step software work: a plan
483
+ note and tasks, approval before any project file changes, then execution with
484
+ per-task status. Small edits and questions skip it. The system prompt is a general assistant;
483
485
  when a skill fits the request, the model loads it itself.
484
486
 
485
487
  The skills enabled for a session are listed in the system prompt under
@@ -488,7 +490,7 @@ model. The `skills` setting chooses them:
488
490
 
489
491
  | `skills` | Enabled skills |
490
492
  |---|---|
491
- | not set | the built-in skills (`engineering`), including your or the project's copy of the same name |
493
+ | not set | the built-in skills (`development-workflow`), including your or the project's copy of the same name |
492
494
  | `"none"` or `[]` | none: no skill tool, no catalog |
493
495
  | `["a", "b"]` | exactly these names, from any layer |
494
496
 
@@ -584,7 +586,7 @@ ayder-cli includes a built-in task system:
584
586
 
585
587
  Tasks are stored as markdown files in `.ayder/tasks/` using slug-based filenames (e.g., `TASK-001-add-auth-middleware.md`).
586
588
 
587
- 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.
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. 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.
588
590
 
589
591
  ```
590
592
  > /tasks # Interactive task browser
@@ -774,7 +776,8 @@ project root, then start Ayder:
774
776
  "local-tools": {
775
777
  "command": "python",
776
778
  "args": ["server.py"],
777
- "env": {"EXAMPLE_SETTING": "value"}
779
+ "env": {"EXAMPLE_SETTING": "value"},
780
+ "parallel": false
778
781
  },
779
782
  "remote-tools": {
780
783
  "url": "http://localhost:8000/mcp"
@@ -790,6 +793,16 @@ is needed. Tool calls retain the usual permissions: `x` for stdio servers and
790
793
  `http` for HTTP servers. Configure only servers you intend Ayder to connect to:
791
794
  local server commands start during runtime initialization to discover tools.
792
795
 
796
+ Calls to MCP tools in one response run at the same time by default. Set
797
+ `"parallel": false` on a server to run its calls one at a time, in the order the
798
+ model sent them. Do this for servers that write local files, so a read sent in
799
+ the same response cannot see the file before the write. `"parallel": true` runs
800
+ all of a server's tools concurrently, whatever the server declares. Without the
801
+ key, the server's own tool annotations decide: a tool marked `readOnlyHint`
802
+ runs concurrently, and one marked `readOnlyHint: false` or `destructiveHint`
803
+ runs alone. MCP calls always wait for built-in tools that change things
804
+ (`file_editor`, `bash`, ...) sent before them.
805
+
793
806
  Tools keep their server-provided names unless they conflict with an existing
794
807
  tool; conflicting names receive a `server__` prefix (and a numeric suffix if
795
808
  needed). Unreachable servers are skipped so other tools remain available.
@@ -39,7 +39,7 @@ LLMs on their own can only generate text. To be a useful coding assistant, the m
39
39
 
40
40
  Each tool has an OpenAI-compatible JSON schema so models that support function calling can use them natively. For models that don't, ayder-cli also parses a custom XML-like syntax (`<function=name><parameter=key>value</parameter></function>`) as a fallback.
41
41
 
42
- - **Path sandboxing**: All file operations are confined to the project root via `ProjectContext`. Path traversal attacks (`../`) and absolute paths outside the project are blocked.
42
+ - **Path sandboxing**: All file operations are confined to the project root via `ProjectContext`. Path traversal attacks (`../`) and absolute paths outside the project are blocked. The one exception is the session scratch directory, `/tmp/ayder-<uid>/<project>-<hash>/<session>/` (mode 0700, one subdirectory per agent run), which the system prompt names as the place for temporary files and which the file tools accept. It is not cleaned up; the OS clears `/tmp`.
43
43
  - **Safe mode** (TUI): Blocks `file_editor`, `run_shell_command`, `run_background_process`, `kill_background_process`, and `fetch_web`.
44
44
  - Every tool call requires your confirmation before it runs -- you always stay in control. Use `-r`, `-w`, `-x` flags to auto-approve tool categories.
45
45
  - You may also prefer to run ayder-cli in a container for additional security.
@@ -160,12 +160,12 @@ 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
167
167
  tool_tags = ["core", "metadata"] # Enabled tool tags (see /plugin)
168
- # skills = ["engineering"] # or "none"; default: the built-in skills
168
+ # skills = ["development-workflow"] # or "none"; default: the built-in skills
169
169
  agent_timeout = 300 # Seconds before a background agent is cancelled
170
170
 
171
171
  [logging]
@@ -311,7 +311,8 @@ ayder -f instructions.txt
311
311
  ayder --stdin < prompt.txt
312
312
 
313
313
  # Override the main LLM system prompt with a file
314
- # (tool instructions are still appended)
314
+ # (the environment section with working directory and start time,
315
+ # and the tool instructions, are still appended)
315
316
  ayder --system-prompt prompt-file.md "refactor this code"
316
317
  ```
317
318
 
@@ -435,8 +436,9 @@ later one overrides an earlier one with the same name:
435
436
  2. your skills in `~/.ayder/skills/<name>/`
436
437
  3. project skills in `<project>/.ayder/skills/<name>/`
437
438
 
438
- ayder ships an `engineering` skill (build, change, debug or review code;
439
- research; plan multi-step work). The system prompt is a general assistant;
439
+ ayder ships a `development-workflow` skill for multi-step software work: a plan
440
+ note and tasks, approval before any project file changes, then execution with
441
+ per-task status. Small edits and questions skip it. The system prompt is a general assistant;
440
442
  when a skill fits the request, the model loads it itself.
441
443
 
442
444
  The skills enabled for a session are listed in the system prompt under
@@ -445,7 +447,7 @@ model. The `skills` setting chooses them:
445
447
 
446
448
  | `skills` | Enabled skills |
447
449
  |---|---|
448
- | not set | the built-in skills (`engineering`), including your or the project's copy of the same name |
450
+ | not set | the built-in skills (`development-workflow`), including your or the project's copy of the same name |
449
451
  | `"none"` or `[]` | none: no skill tool, no catalog |
450
452
  | `["a", "b"]` | exactly these names, from any layer |
451
453
 
@@ -541,7 +543,7 @@ ayder-cli includes a built-in task system:
541
543
 
542
544
  Tasks are stored as markdown files in `.ayder/tasks/` using slug-based filenames (e.g., `TASK-001-add-auth-middleware.md`).
543
545
 
544
- 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.
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. 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.
545
547
 
546
548
  ```
547
549
  > /tasks # Interactive task browser
@@ -731,7 +733,8 @@ project root, then start Ayder:
731
733
  "local-tools": {
732
734
  "command": "python",
733
735
  "args": ["server.py"],
734
- "env": {"EXAMPLE_SETTING": "value"}
736
+ "env": {"EXAMPLE_SETTING": "value"},
737
+ "parallel": false
735
738
  },
736
739
  "remote-tools": {
737
740
  "url": "http://localhost:8000/mcp"
@@ -747,6 +750,16 @@ is needed. Tool calls retain the usual permissions: `x` for stdio servers and
747
750
  `http` for HTTP servers. Configure only servers you intend Ayder to connect to:
748
751
  local server commands start during runtime initialization to discover tools.
749
752
 
753
+ Calls to MCP tools in one response run at the same time by default. Set
754
+ `"parallel": false` on a server to run its calls one at a time, in the order the
755
+ model sent them. Do this for servers that write local files, so a read sent in
756
+ the same response cannot see the file before the write. `"parallel": true` runs
757
+ all of a server's tools concurrently, whatever the server declares. Without the
758
+ key, the server's own tool annotations decide: a tool marked `readOnlyHint`
759
+ runs concurrently, and one marked `readOnlyHint: false` or `destructiveHint`
760
+ runs alone. MCP calls always wait for built-in tools that change things
761
+ (`file_editor`, `bash`, ...) sent before them.
762
+
750
763
  Tools keep their server-provided names unless they conflict with an existing
751
764
  tool; conflicting names receive a `server__` prefix (and a numeric suffix if
752
765
  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: `2707 passed, 2 skipped` on `chore/prompt-tests-injection-only` (2026-10-16).
15
+ Last measured: `2909 passed, 2 skipped` on `fix/docs-skill-list-2.5.2` (2026-10-22, release 2.5.2).
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
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
 
@@ -594,7 +594,7 @@ AyderApp is the main Textual application implementing a chat-style interface:
594
594
  The application manages:
595
595
  - LLM provider setup and configuration
596
596
  - Tool registry initialization with middleware
597
- - System prompt construction (base prompt + tool prompts + skill catalog; no project tree)
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. 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
598
  - Process manager for background operations
599
599
 
600
600
  ### Chat Loop Summary (src/ayder_cli/loops/chat_loop.py)
@@ -609,7 +609,7 @@ previously-split `AgentLoopBase` and `LoopConfig` were merged back in):
609
609
  - 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
610
 
611
611
  Key features:
612
- - Auto-approved tools run in parallel (`asyncio.as_completed`); confirmation-required tools run sequentially
612
+ - 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
613
  - Confirmation gate applies to **both** OpenAI-format and XML/JSON custom tool calls
614
614
  - `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
615
  - 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 +645,7 @@ Schema-driven tool definitions with auto-discovery:
645
645
  - **Required-tool validation**: Raises `ImportError` if core tools (`file_explorer`, `read_file`, `file_editor`, `bash`) are absent
646
646
  - **Permissions**: `"r"` (read), `"w"` (write), `"x"` (execute), `"http"` (network)
647
647
  - **Safety flags**: `safe_mode_blocked`, `is_terminal` per definition
648
+ - **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
649
  - **Path parameters**: Names listed in `path_parameters` are automatically resolved via `ProjectContext`
649
650
  - **Aliases**: `parameter_aliases` tuples for common name normalisation
650
651
  - **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
@@ -100,7 +102,7 @@ tool_tags = ["core", "metadata", "background", "http"]
100
102
  # Skills the session's model may load (listed under "### Skills" in the system
101
103
  # prompt). Not set = the built-in skills; "none" = no skill tool; or a strict
102
104
  # list. A [llm.*] profile's skills wins over this one for the session.
103
- # skills = ["engineering"]
105
+ # skills = ["development-workflow"]
104
106
 
105
107
  [ui]
106
108
  # TUI layout (theme) — picks the chrome/layout:
@@ -229,9 +231,10 @@ think = true # default; set false if the selected model r
229
231
  [agents.pm_spec]
230
232
  provider = "ollama_cloud"
231
233
  model = "glm-5.2:cloud"
232
- # skills = ["engineering"] # wins over the provider profile's skills; [app] is never read
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.0"
7
+ version = "2.5.2"
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:
@@ -384,7 +384,9 @@ class AgentRegistry:
384
384
  worktree_path = wt_dir
385
385
  self._session_worktrees.add(wt_dir)
386
386
  run.worktree_path = wt_dir
387
- project_ctx = ProjectContext(wt_dir)
387
+ project_ctx = ProjectContext(
388
+ wt_dir, scratch_dir=self._project_ctx.scratch_dir
389
+ )
388
390
  head_before = await asyncio.to_thread(
389
391
  branch_head, repo_root, run.branch_name
390
392
  )