ayder-cli 2.4.1__tar.gz → 2.5.1__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 (352) hide show
  1. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/.github/workflows/python-package.yml +3 -0
  2. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/PKG-INFO +48 -7
  3. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/README.md +47 -6
  4. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/docs/GATE.md +1 -1
  5. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/docs/PROJECT_STRUCTURE.md +9 -3
  6. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/docs/config.toml.example +6 -0
  7. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/pyproject.toml +1 -1
  8. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/scripts/check_exception_handlers.py +1 -1
  9. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/scripts/check_log_arguments.py +7 -7
  10. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/scripts/log_argument_baseline.txt +5 -0
  11. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/agents/config.py +10 -2
  12. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/agents/registry.py +3 -1
  13. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/application/runtime_factory.py +52 -14
  14. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/core/config.py +38 -1
  15. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/core/context.py +65 -3
  16. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/core/default_context_manager.py +73 -31
  17. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/core/ollama_context_manager.py +73 -6
  18. ayder_cli-2.5.1/src/ayder_cli/core/skills.py +499 -0
  19. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/loops/chat_loop.py +4 -0
  20. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/prompts.py +63 -103
  21. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/providers/impl/ollama_drivers/generic_xml.py +1 -1
  22. ayder_cli-2.5.1/src/ayder_cli/skills/development-workflow/SKILL.md +27 -0
  23. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/builtins/filesystem_definitions.py +4 -4
  24. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/builtins/shell_definitions.py +2 -1
  25. ayder_cli-2.5.1/src/ayder_cli/tools/builtins/skill.py +150 -0
  26. ayder_cli-2.5.1/src/ayder_cli/tools/builtins/skill_definitions.py +54 -0
  27. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/builtins/task_definitions.py +12 -5
  28. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/builtins/task_tool.py +107 -12
  29. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/definition.py +22 -1
  30. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/execution.py +4 -1
  31. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/registry.py +25 -9
  32. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tui/app.py +6 -66
  33. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tui/commands.py +62 -45
  34. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/agents/test_worktree_isolation.py +27 -0
  35. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/application/test_runtime_factory.py +10 -25
  36. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/conftest.py +25 -0
  37. ayder_cli-2.5.1/tests/core/test_config_skills.py +78 -0
  38. ayder_cli-2.5.1/tests/core/test_default_context_skill_resupply.py +178 -0
  39. ayder_cli-2.5.1/tests/core/test_ollama_skill_resupply.py +151 -0
  40. ayder_cli-2.5.1/tests/core/test_scratch_dir.py +115 -0
  41. ayder_cli-2.5.1/tests/core/test_skills.py +240 -0
  42. ayder_cli-2.5.1/tests/core/test_skills_builtin_sync.py +147 -0
  43. ayder_cli-2.5.1/tests/providers/test_skill_load_prefix.py +90 -0
  44. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/scripts/test_exception_gate.py +9 -5
  45. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/scripts/test_log_argument_gate.py +16 -16
  46. ayder_cli-2.5.1/tests/test_prompts_environment.py +102 -0
  47. ayder_cli-2.5.1/tests/test_prompts_general.py +33 -0
  48. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_definition_discovery.py +39 -0
  49. ayder_cli-2.5.1/tests/tools/test_skill_catalog_and_filter.py +182 -0
  50. ayder_cli-2.5.1/tests/tools/test_skill_scope_wiring.py +57 -0
  51. ayder_cli-2.5.1/tests/tools/test_skill_tool.py +178 -0
  52. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_task_tool.py +114 -3
  53. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tui/test_turn_consumer.py +0 -66
  54. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/ui/test_tui_commands_provider.py +3 -0
  55. ayder_cli-2.5.1/tests/ui/test_tui_commands_skill.py +155 -0
  56. ayder_cli-2.5.1/tests/ui/test_tui_system_prompt_no_structure.py +54 -0
  57. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/uv.lock +2 -2
  58. ayder_cli-2.4.1/src/ayder_cli/tools/builtins/skill.py +0 -238
  59. ayder_cli-2.4.1/src/ayder_cli/tools/builtins/skill_definitions.py +0 -47
  60. ayder_cli-2.4.1/tests/tools/test_skill_tool.py +0 -220
  61. ayder_cli-2.4.1/tests/ui/test_tui_commands_skill.py +0 -116
  62. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/.github/workflows/ci.yml +0 -0
  63. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/.gitignore +0 -0
  64. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/.python-version +0 -0
  65. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/AGENTS.md +0 -0
  66. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/LICENSE +0 -0
  67. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/docs/README_AGENT_WORKFLOW.md +0 -0
  68. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/docs/README_OLLAMA.md +0 -0
  69. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/docs/cc.png +0 -0
  70. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/docs/superpowers/plans/2026-06-26-file-editor-improvements.md +0 -0
  71. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/docs/superpowers/plans/2026-06-26-session-save-resume.md +0 -0
  72. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/docs/superpowers/specs/2026-06-26-file-editor-improvements-design.md +0 -0
  73. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/docs/superpowers/specs/2026-06-26-session-save-resume-design.md +0 -0
  74. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/scripts/check_logging_imports.py +0 -0
  75. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/scripts/exception_baseline.txt +0 -0
  76. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/scripts/find_percent_logging.py +0 -0
  77. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/scripts/logging_gates.py +0 -0
  78. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/__init__.py +0 -0
  79. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/__main__.py +0 -0
  80. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/agents/__init__.py +0 -0
  81. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/agents/callbacks.py +0 -0
  82. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/agents/run.py +0 -0
  83. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/agents/runner.py +0 -0
  84. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/agents/tool.py +0 -0
  85. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/agents/worktree.py +0 -0
  86. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/application/README.md +0 -0
  87. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/application/__init__.py +0 -0
  88. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/application/execution_policy.py +0 -0
  89. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/application/message_contract.py +0 -0
  90. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/application/validation.py +0 -0
  91. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/cli.py +0 -0
  92. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/cli_callbacks.py +0 -0
  93. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/cli_runner.py +0 -0
  94. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/console.py +0 -0
  95. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/core/cache_monitor.py +0 -0
  96. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/core/config_migration.py +0 -0
  97. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/core/context_manager.py +0 -0
  98. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/core/context_manager_factory.py +0 -0
  99. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/core/reasoning.py +0 -0
  100. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/core/result.py +0 -0
  101. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/core/session.py +0 -0
  102. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/diagnostics.py +0 -0
  103. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/log.py +0 -0
  104. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/logging_config.py +0 -0
  105. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/loops/__init__.py +0 -0
  106. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/masking.py +0 -0
  107. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/parser.py +0 -0
  108. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/process_manager.py +0 -0
  109. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/providers/__init__.py +0 -0
  110. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/providers/base.py +0 -0
  111. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/providers/evren.py +0 -0
  112. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/providers/impl/claude.py +0 -0
  113. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/providers/impl/deepseek.py +0 -0
  114. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/providers/impl/gemini.py +0 -0
  115. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/providers/impl/glm.py +0 -0
  116. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/providers/impl/ollama.py +0 -0
  117. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/providers/impl/ollama_drivers/__init__.py +0 -0
  118. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/providers/impl/ollama_drivers/_errors.py +0 -0
  119. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/providers/impl/ollama_drivers/base.py +0 -0
  120. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/providers/impl/ollama_drivers/deepseek.py +0 -0
  121. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/providers/impl/ollama_drivers/generic_native.py +0 -0
  122. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/providers/impl/ollama_drivers/matrix.py +0 -0
  123. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/providers/impl/ollama_drivers/minimax.py +0 -0
  124. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/providers/impl/ollama_drivers/qwen3.py +0 -0
  125. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/providers/impl/ollama_drivers/registry.py +0 -0
  126. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/providers/impl/ollama_inspector.py +0 -0
  127. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/providers/impl/openai.py +0 -0
  128. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/providers/impl/qwen.py +0 -0
  129. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/providers/orchestrator.py +0 -0
  130. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/providers/retry.py +0 -0
  131. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/services/__init__.py +0 -0
  132. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/services/interactions.py +0 -0
  133. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/services/messaging_inbox.py +0 -0
  134. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/themes/__init__.py +0 -0
  135. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/themes/ayder.py +0 -0
  136. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/themes/claude.py +0 -0
  137. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/__init__.py +0 -0
  138. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/builtins/__init__.py +0 -0
  139. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/builtins/background_process_tool.py +0 -0
  140. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/builtins/context.py +0 -0
  141. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/builtins/context_definitions.py +0 -0
  142. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/builtins/filesystem.py +0 -0
  143. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/builtins/note_tool.py +0 -0
  144. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/builtins/notes.py +0 -0
  145. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/builtins/notes_definitions.py +0 -0
  146. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/builtins/process_manager_definitions.py +0 -0
  147. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/builtins/search.py +0 -0
  148. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/builtins/search_definitions.py +0 -0
  149. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/builtins/shell.py +0 -0
  150. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/builtins/tasks.py +0 -0
  151. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/builtins/utils_tools.py +0 -0
  152. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/builtins/utils_tools_definitions.py +0 -0
  153. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/builtins/web.py +0 -0
  154. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/builtins/web_definitions.py +0 -0
  155. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/hooks.py +0 -0
  156. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/mcp.py +0 -0
  157. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/mcp_client.py +0 -0
  158. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/normalization.py +0 -0
  159. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/plugin_api.py +0 -0
  160. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/plugin_github.py +0 -0
  161. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/plugin_manager.py +0 -0
  162. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/plugin_status.py +0 -0
  163. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/schemas.py +0 -0
  164. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tools/utils.py +0 -0
  165. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tui/__init__.py +0 -0
  166. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tui/adapter.py +0 -0
  167. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tui/helpers.py +0 -0
  168. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tui/keybindings.py +0 -0
  169. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tui/parser.py +0 -0
  170. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tui/rendering.py +0 -0
  171. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tui/screens.py +0 -0
  172. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tui/theme_manager.py +0 -0
  173. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tui/types.py +0 -0
  174. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/tui/widgets.py +0 -0
  175. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/ui.py +0 -0
  176. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/src/ayder_cli/version.py +0 -0
  177. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/COVERAGE.md +0 -0
  178. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/__init__.py +0 -0
  179. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/agents/__init__.py +0 -0
  180. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/agents/test_agent_consolidated.py +0 -0
  181. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/agents/test_agent_severity.py +0 -0
  182. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/agents/test_agent_tools.py +0 -0
  183. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/agents/test_callbacks.py +0 -0
  184. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/agents/test_config.py +0 -0
  185. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/agents/test_integration.py +0 -0
  186. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/agents/test_queue.py +0 -0
  187. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/agents/test_registry.py +0 -0
  188. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/agents/test_run.py +0 -0
  189. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/agents/test_runner.py +0 -0
  190. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/agents/test_runner_provider_unavailable.py +0 -0
  191. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/agents/test_tool.py +0 -0
  192. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/agents/test_worktree_helpers.py +0 -0
  193. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/application/test_argument_canonicalization.py +0 -0
  194. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/application/test_execution_result_truthfulness.py +0 -0
  195. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/application/test_message_contract.py +0 -0
  196. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/client/test_main.py +0 -0
  197. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/convergence/__init__.py +0 -0
  198. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/convergence/test_execution_policy_parity.py +0 -0
  199. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/convergence/test_runtime_wiring.py +0 -0
  200. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/convergence/test_validation_path.py +0 -0
  201. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_asyncio_bridge.py +0 -0
  202. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_cache_monitor.py +0 -0
  203. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_config.py +0 -0
  204. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_config_coverage.py +0 -0
  205. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_config_migration.py +0 -0
  206. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_config_provider_logging.py +0 -0
  207. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_config_retry.py +0 -0
  208. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_config_v2.py +0 -0
  209. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_context_manager_factory.py +0 -0
  210. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_default_config_evren.py +0 -0
  211. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_default_context_manager.py +0 -0
  212. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_default_context_manager_should_compact.py +0 -0
  213. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_default_context_newest_unit.py +0 -0
  214. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_event_emission.py +0 -0
  215. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_event_stream.py +0 -0
  216. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_exception_guarantee.py +0 -0
  217. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_exception_hooks.py +0 -0
  218. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_log_facade.py +0 -0
  219. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_logging_config_keys.py +0 -0
  220. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_logging_sinks.py +0 -0
  221. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_loguru_caplog.py +0 -0
  222. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_max_output_tokens_default.py +0 -0
  223. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_ollama_compaction_persistence.py +0 -0
  224. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_ollama_context_manager.py +0 -0
  225. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_ollama_context_manager_cache_monitor.py +0 -0
  226. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_ollama_context_manager_max_history.py +0 -0
  227. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_parameter_aliasing.py +0 -0
  228. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_parser.py +0 -0
  229. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_reasoning_config.py +0 -0
  230. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_session.py +0 -0
  231. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_session_id_threading.py +0 -0
  232. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/core/test_sink_masking.py +0 -0
  233. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/loops/__init__.py +0 -0
  234. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/loops/test_base.py +0 -0
  235. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/loops/test_chat_loop_hook.py +0 -0
  236. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/loops/test_chat_loop_tool_truncation.py +0 -0
  237. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/loops/test_loop_severity.py +0 -0
  238. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/loops/test_required_args_aliases.py +0 -0
  239. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/loops/test_tool_argument_integrity.py +0 -0
  240. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/loops/test_tool_batch_cancellation.py +0 -0
  241. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/__init__.py +0 -0
  242. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/ollama_drivers/__init__.py +0 -0
  243. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/ollama_drivers/test_base.py +0 -0
  244. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/ollama_drivers/test_deepseek.py +0 -0
  245. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/ollama_drivers/test_errors.py +0 -0
  246. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/ollama_drivers/test_fallback.py +0 -0
  247. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/ollama_drivers/test_generic_native.py +0 -0
  248. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/ollama_drivers/test_generic_xml.py +0 -0
  249. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/ollama_drivers/test_matrix.py +0 -0
  250. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/ollama_drivers/test_minimax.py +0 -0
  251. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/ollama_drivers/test_provider_integration.py +0 -0
  252. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/ollama_drivers/test_qwen3.py +0 -0
  253. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/ollama_drivers/test_registry.py +0 -0
  254. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/test_claude_stream_tool_calls.py +0 -0
  255. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/test_evren.py +0 -0
  256. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/test_gemini_function_calls.py +0 -0
  257. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/test_glm_async.py +0 -0
  258. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/test_ollama_inspector.py +0 -0
  259. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/test_ollama_native.py +0 -0
  260. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/test_ollama_parallel_tool_call_ids.py +0 -0
  261. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/test_ollama_xml.py +0 -0
  262. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/test_ollama_xml_autoroute.py +0 -0
  263. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/test_ollama_xml_usage.py +0 -0
  264. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/test_openai_list_models.py +0 -0
  265. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/test_orchestrator_capabilities.py +0 -0
  266. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/test_provider_channel_binding.py +0 -0
  267. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/test_provider_severity.py +0 -0
  268. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/test_qwen_async.py +0 -0
  269. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/test_reasoning_effort.py +0 -0
  270. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/test_retry_classifier.py +0 -0
  271. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/test_retry_integration.py +0 -0
  272. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/providers/test_retrying_provider.py +0 -0
  273. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/scripts/test_logging_policy_gates.py +0 -0
  274. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/scripts/test_loguru_private_shape.py +0 -0
  275. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/services/test_boundary.py +0 -0
  276. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/services/test_interaction_sink.py +0 -0
  277. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/services/test_messaging_inbox.py +0 -0
  278. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/test_cli.py +0 -0
  279. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/test_cli_callbacks.py +0 -0
  280. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/test_context.py +0 -0
  281. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/test_env_manager.py +0 -0
  282. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/test_logging_config.py +0 -0
  283. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/test_notes.py +0 -0
  284. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/test_process_manager.py +0 -0
  285. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/test_tasks.py +0 -0
  286. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/__init__.py +0 -0
  287. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_agent_notes.py +0 -0
  288. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_background_process_tool.py +0 -0
  289. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_bash_tool.py +0 -0
  290. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_context_storage_confinement.py +0 -0
  291. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_di_injection.py +0 -0
  292. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_file_editor_hardening.py +0 -0
  293. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_file_editor_size_limit.py +0 -0
  294. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_impl.py +0 -0
  295. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_impl_coverage.py +0 -0
  296. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_mcp.py +0 -0
  297. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_mcp_client.py +0 -0
  298. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_note_tool.py +0 -0
  299. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_notes_api.py +0 -0
  300. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_notes_confinement.py +0 -0
  301. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_path_security.py +0 -0
  302. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_plugin_api.py +0 -0
  303. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_plugin_github.py +0 -0
  304. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_plugin_loading.py +0 -0
  305. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_plugin_manager.py +0 -0
  306. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_plugin_status.py +0 -0
  307. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_registry.py +0 -0
  308. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_registry_coverage.py +0 -0
  309. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_result.py +0 -0
  310. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_schemas.py +0 -0
  311. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_search_codebase.py +0 -0
  312. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_search_hardening.py +0 -0
  313. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_task_path_confinement.py +0 -0
  314. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_tool_severity.py +0 -0
  315. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_unexpected_args.py +0 -0
  316. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_utils.py +0 -0
  317. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tools/test_web.py +0 -0
  318. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tui/__init__.py +0 -0
  319. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tui/test_agent_list_screen.py +0 -0
  320. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tui/test_do_clear_coordination.py +0 -0
  321. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tui/test_evren_terms.py +0 -0
  322. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tui/test_follow_mode.py +0 -0
  323. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tui/test_help_screen.py +0 -0
  324. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tui/test_input_box.py +0 -0
  325. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tui/test_keybindings.py +0 -0
  326. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tui/test_multi_select_screen.py +0 -0
  327. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tui/test_multiline_input.py +0 -0
  328. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tui/test_paste.py +0 -0
  329. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tui/test_peer_message_turn.py +0 -0
  330. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tui/test_pending_compact_consumer.py +0 -0
  331. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tui/test_pull_delivery.py +0 -0
  332. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tui/test_resume.py +0 -0
  333. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tui/test_status_bar_badges.py +0 -0
  334. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tui/test_themes.py +0 -0
  335. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/tui/test_widgets.py +0 -0
  336. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/ui/test_confirm_screen.py +0 -0
  337. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/ui/test_diff_preview.py +0 -0
  338. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/ui/test_plugin_autoenable.py +0 -0
  339. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/ui/test_provider_switch.py +0 -0
  340. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/ui/test_run_tui_startup.py +0 -0
  341. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/ui/test_tui_assistant_sanitization.py +0 -0
  342. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/ui/test_tui_chat_loop.py +0 -0
  343. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/ui/test_tui_commands_agent.py +0 -0
  344. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/ui/test_tui_commands_effort.py +0 -0
  345. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/ui/test_tui_commands_logging.py +0 -0
  346. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/ui/test_tui_commands_plugin.py +0 -0
  347. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/ui/test_tui_helpers.py +0 -0
  348. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/ui/test_tui_temporal_command.py +0 -0
  349. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/ui/test_tui_widgets.py +0 -0
  350. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/ui/test_ui.py +0 -0
  351. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/tests/ui/test_ui_coverage.py +0 -0
  352. {ayder_cli-2.4.1 → ayder_cli-2.5.1}/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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ayder-cli
3
- Version: 2.4.1
3
+ Version: 2.5.1
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.
@@ -208,6 +208,7 @@ 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 = ["development-workflow"] # or "none"; default: the built-in skills
211
212
  agent_timeout = 300 # Seconds before a background agent is cancelled
212
213
 
213
214
  [logging]
@@ -353,7 +354,8 @@ ayder -f instructions.txt
353
354
  ayder --stdin < prompt.txt
354
355
 
355
356
  # Override the main LLM system prompt with a file
356
- # (tool instructions + project structure are still appended)
357
+ # (the environment section with working directory and start time,
358
+ # and the tool instructions, are still appended)
357
359
  ayder --system-prompt prompt-file.md "refactor this code"
358
360
  ```
359
361
 
@@ -452,7 +454,7 @@ You can also manually manage context with the `context` tool and its slash-comma
452
454
  | `/tasks` | Browse and implement tasks from `.ayder/tasks/` |
453
455
  | `/implement [id]` | Interactive task picker, or implement by ID (e.g., `/implement 1`) |
454
456
  | `/notes` | Browse and edit markdown notes |
455
- | `/skill` | Activate a domain skill from `.ayder/skills/` via the shared `skill` tool backend |
457
+ | `/skill` | Load a skill as a user message: `/skill <name> [request]`, or pick one |
456
458
  | `/verbose` | Toggle verbose mode |
457
459
  | `/logging` | Set log level for current session (NONE, ERROR, WARNING, INFO, DEBUG, TRACE) |
458
460
  | `/compact` | Summarize conversation, save a context snapshot, clear, and reload |
@@ -466,10 +468,48 @@ You can also manually manage context with the `context` tool and its slash-comma
466
468
  | `/agent <name> <task>` | Dispatch an agent to run a task in the background |
467
469
  | `/agent cancel <name>` | Cancel a running agent |
468
470
 
469
- ### Logging
471
+ ### Skills
472
+
473
+ A skill is a directory with a `SKILL.md` file, optionally starting with
474
+ `name:` and `description:` frontmatter. ayder looks in three places, and a
475
+ later one overrides an earlier one with the same name:
476
+
477
+ 1. built-in skills in `~/.ayder/builtin/skills/`, managed by ayder and
478
+ replaced on upgrade; to customize one, copy it to `~/.ayder/skills/<name>/`
479
+ 2. your skills in `~/.ayder/skills/<name>/`
480
+ 3. project skills in `<project>/.ayder/skills/<name>/`
481
+
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;
485
+ when a skill fits the request, the model loads it itself.
486
+
487
+ The skills enabled for a session are listed in the system prompt under
488
+ "### Skills" (name and description), and only those can be loaded by the
489
+ model. The `skills` setting chooses them:
490
+
491
+ | `skills` | Enabled skills |
492
+ |---|---|
493
+ | not set | the built-in skills (`development-workflow`), including your or the project's copy of the same name |
494
+ | `"none"` or `[]` | none: no skill tool, no catalog |
495
+ | `["a", "b"]` | exactly these names, from any layer |
496
+
497
+ The main session reads `[llm.<provider>].skills`, then `[app].skills`. An
498
+ agent reads `[agents.<name>].skills`, then its provider profile's; never
499
+ `[app]`. The `/skill` command loads any discovered skill, including project
500
+ skills that are not in the catalog.
501
+
502
+ The model loads one with `skill(action="load", name=...)`; the instructions
503
+ come back as the tool result, so the conversation's earlier messages (and the
504
+ provider's KV cache) are unchanged. Several skills can be active; other files
505
+ in a skill's directory are read on demand with `skill(action="read")`.
506
+ A skill directory or `SKILL.md` that links outside its skills directory is
507
+ listed but never read or loaded; copy the skill instead of symlinking it.
508
+ A loaded skill stays in context for the whole session: when trimming or
509
+ compaction removes it, ayder adds it back right after the system prompt, or
510
+ inside the Ollama summary.
470
511
 
471
- The LLM can also call `skill(action="list" | "load" | "unload")`
472
- automatically when a request clearly matches an available project skill.
512
+ ### Logging
473
513
 
474
514
  - Errors are always captured to `.ayder/log/errors.log`, even when
475
515
  `logging_level` is `NONE`. Set `file_enabled = false` under `[logging]` to
@@ -670,6 +710,7 @@ Each agent field:
670
710
  | `system_prompt` | Yes | The agent's role and instructions |
671
711
  | `provider` | No | LLM provider profile name (inherits from `[app]` if omitted) |
672
712
  | `model` | No | Model name override (inherits from provider profile if omitted) |
713
+ | `skills` | No | `"none"` or a list of skill names (inherits from the provider profile; default: the built-in skills) |
673
714
 
674
715
  ### Using Agents
675
716
 
@@ -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.
@@ -165,6 +165,7 @@ 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 = ["development-workflow"] # or "none"; default: the built-in skills
168
169
  agent_timeout = 300 # Seconds before a background agent is cancelled
169
170
 
170
171
  [logging]
@@ -310,7 +311,8 @@ ayder -f instructions.txt
310
311
  ayder --stdin < prompt.txt
311
312
 
312
313
  # Override the main LLM system prompt with a file
313
- # (tool instructions + project structure are still appended)
314
+ # (the environment section with working directory and start time,
315
+ # and the tool instructions, are still appended)
314
316
  ayder --system-prompt prompt-file.md "refactor this code"
315
317
  ```
316
318
 
@@ -409,7 +411,7 @@ You can also manually manage context with the `context` tool and its slash-comma
409
411
  | `/tasks` | Browse and implement tasks from `.ayder/tasks/` |
410
412
  | `/implement [id]` | Interactive task picker, or implement by ID (e.g., `/implement 1`) |
411
413
  | `/notes` | Browse and edit markdown notes |
412
- | `/skill` | Activate a domain skill from `.ayder/skills/` via the shared `skill` tool backend |
414
+ | `/skill` | Load a skill as a user message: `/skill <name> [request]`, or pick one |
413
415
  | `/verbose` | Toggle verbose mode |
414
416
  | `/logging` | Set log level for current session (NONE, ERROR, WARNING, INFO, DEBUG, TRACE) |
415
417
  | `/compact` | Summarize conversation, save a context snapshot, clear, and reload |
@@ -423,10 +425,48 @@ You can also manually manage context with the `context` tool and its slash-comma
423
425
  | `/agent <name> <task>` | Dispatch an agent to run a task in the background |
424
426
  | `/agent cancel <name>` | Cancel a running agent |
425
427
 
426
- ### Logging
428
+ ### Skills
429
+
430
+ A skill is a directory with a `SKILL.md` file, optionally starting with
431
+ `name:` and `description:` frontmatter. ayder looks in three places, and a
432
+ later one overrides an earlier one with the same name:
433
+
434
+ 1. built-in skills in `~/.ayder/builtin/skills/`, managed by ayder and
435
+ replaced on upgrade; to customize one, copy it to `~/.ayder/skills/<name>/`
436
+ 2. your skills in `~/.ayder/skills/<name>/`
437
+ 3. project skills in `<project>/.ayder/skills/<name>/`
438
+
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;
442
+ when a skill fits the request, the model loads it itself.
443
+
444
+ The skills enabled for a session are listed in the system prompt under
445
+ "### Skills" (name and description), and only those can be loaded by the
446
+ model. The `skills` setting chooses them:
447
+
448
+ | `skills` | Enabled skills |
449
+ |---|---|
450
+ | not set | the built-in skills (`development-workflow`), including your or the project's copy of the same name |
451
+ | `"none"` or `[]` | none: no skill tool, no catalog |
452
+ | `["a", "b"]` | exactly these names, from any layer |
453
+
454
+ The main session reads `[llm.<provider>].skills`, then `[app].skills`. An
455
+ agent reads `[agents.<name>].skills`, then its provider profile's; never
456
+ `[app]`. The `/skill` command loads any discovered skill, including project
457
+ skills that are not in the catalog.
458
+
459
+ The model loads one with `skill(action="load", name=...)`; the instructions
460
+ come back as the tool result, so the conversation's earlier messages (and the
461
+ provider's KV cache) are unchanged. Several skills can be active; other files
462
+ in a skill's directory are read on demand with `skill(action="read")`.
463
+ A skill directory or `SKILL.md` that links outside its skills directory is
464
+ listed but never read or loaded; copy the skill instead of symlinking it.
465
+ A loaded skill stays in context for the whole session: when trimming or
466
+ compaction removes it, ayder adds it back right after the system prompt, or
467
+ inside the Ollama summary.
427
468
 
428
- The LLM can also call `skill(action="list" | "load" | "unload")`
429
- automatically when a request clearly matches an available project skill.
469
+ ### Logging
430
470
 
431
471
  - Errors are always captured to `.ayder/log/errors.log`, even when
432
472
  `logging_level` is `NONE`. Set `file_enabled = false` under `[logging]` to
@@ -627,6 +667,7 @@ Each agent field:
627
667
  | `system_prompt` | Yes | The agent's role and instructions |
628
668
  | `provider` | No | LLM provider profile name (inherits from `[app]` if omitted) |
629
669
  | `model` | No | Model name override (inherits from provider profile if omitted) |
670
+ | `skills` | No | `"none"` or a list of skill names (inherits from the provider profile; default: the built-in skills) |
630
671
 
631
672
  ### Using Agents
632
673
 
@@ -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: `2606 passed, 2 skipped` on `fix/max-output-tokens-default` (2026-10-16).
15
+ Last measured: `2743 passed, 2 skipped` on `fix/session-environment-prompt` (2026-10-19, 2.5.1).
16
16
 
17
17
  ## Report format
18
18
 
@@ -72,6 +72,7 @@ ayder-cli is an AI agent chat client with a modular, layered architecture:
72
72
  │ core/config.py (Pydantic Config) │
73
73
  │ core/context.py (ProjectContext, sandboxing) │
74
74
  │ core/result.py (ToolSuccess, ToolError) │
75
+ │ core/skills.py (skill discovery, delivery) │
75
76
  │ core/context_manager.py (ContextManagerProtocol) │
76
77
  │ core/default_context_manager.py │
77
78
  │ core/ollama_context_manager.py (KV-cache-aware) │
@@ -99,7 +100,7 @@ ayder-cli is an AI agent chat client with a modular, layered architecture:
99
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
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
101
102
  6. **Single Validation Path**: `ValidationAuthority → SchemaValidator` is the only validation stage; schema derived from live `TOOL_DEFINITIONS` registry (no hardcoded lists)
102
- 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`)
103
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`
104
105
 
105
106
  ---
@@ -154,6 +155,8 @@ cli.py:main()
154
155
  | `core/config_migration.py` | TOML config migration helpers | migration routines for schema changes |
155
156
  | `core/context.py` | Project sandboxing | `ProjectContext` |
156
157
  | `core/result.py` | Tool result types | `ToolSuccess`, `ToolError` |
158
+ | `core/skills.py` | Skill discovery, delivery, built-in sync and the session filter | `SkillInfo`, `SkillScope`, `discover_all()`, `render_skill_block()`, `active_skills()`, `builtin_skills_root()`, `build_scope()`, `format_catalog()` |
159
+ | `skills/<name>/SKILL.md` | Packaged built-in skills (data only, shipped in the wheel); synced to `~/.ayder/builtin/skills` when `~/.ayder/builtin/STAMP` (version + SHA-256) differs | - |
157
160
  | `core/context_manager.py` | ContextManager Protocol + shared utilities | `ContextManagerProtocol`, `ContextStats`, `truncate_tool_result()` |
158
161
  | `core/default_context_manager.py` | Tiered context manager for non-Ollama providers | `DefaultContextManager`, `TokenCounter`, `MessageTier` |
159
162
  | `core/ollama_context_manager.py` | KV-cache-aware context manager for Ollama | `OllamaContextManager`, `OllamaContextStats` |
@@ -294,6 +297,7 @@ the design rationale.
294
297
  | `tools/builtins/context.py` | Session context snapshots | `context` |
295
298
  | `tools/builtins/notes.py` | Note-taking tool | `create_note()` |
296
299
  | `tools/builtins/tasks.py` | Task-management tools | `list_tasks()`, `show_task()` |
300
+ | `tools/builtins/skill.py` | Skill tool impl | `skill()`, `discover_skills()` |
297
301
  | `tools/builtins/web.py` | HTTP fetch tool | `fetch_web()` |
298
302
  | `tools/builtins/utils_tools.py` | Misc utility tools | `manage_environment_vars()` |
299
303
  | `tools/builtins/*_definitions.py` | Per-domain tool definitions (9 files) | `TOOL_DEFINITIONS` tuples auto-discovered at import |
@@ -303,7 +307,7 @@ the design rationale.
303
307
  | Module | Purpose | Key Classes/Functions |
304
308
  |--------|---------|----------------------|
305
309
  | `process_manager.py` | Background processes | `ProcessManager`, `background_process()` |
306
- | `prompts.py` | System prompts | `SYSTEM_PROMPT`, `PLANNING_PROMPT_TEMPLATE`, `get_system_prompt()`, `PROJECT_STRUCTURE_MACRO_TEMPLATE` |
310
+ | `prompts.py` | System prompts | `SYSTEM_PROMPT`, `PLANNING_PROMPT_TEMPLATE`, `get_system_prompt()` |
307
311
  | `parser.py` | XML tool-call parsing | `parse_custom_tool_calls()` |
308
312
 
309
313
  ### Theme Modules
@@ -590,7 +594,7 @@ AyderApp is the main Textual application implementing a chat-style interface:
590
594
  The application manages:
591
595
  - LLM provider setup and configuration
592
596
  - Tool registry initialization with middleware
593
- - System prompt construction with project structure
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.
594
598
  - Process manager for background operations
595
599
 
596
600
  ### Chat Loop Summary (src/ayder_cli/loops/chat_loop.py)
@@ -719,6 +723,8 @@ Schema-driven tool definitions with auto-discovery:
719
723
  - `OllamaContextManager` (`core/ollama_context_manager.py`) — stable-prefix + real-token accounting, uses `prompt_eval_count` / `prompt_eval_duration` directly.
720
724
  - `CacheMonitor` (`core/cache_monitor.py`) — timing-based KV-cache hit detection driving adaptive compaction thresholds.
721
725
 
726
+ Both managers re-supply active skills that a trim or compaction removed (`core/skills.py` `active_skills`).
727
+
722
728
  Selection lives in `core/context_manager_factory.py` (driver → class path registry). `create_runtime()` owns instantiation and calls `freeze_system_prompt()` once.
723
729
 
724
730
  ### Phase — opus47 critical fixes (2026-04-16)
@@ -97,6 +97,10 @@ agent_timeout = 1800 # seconds before a background agent is cancel
97
97
  # tasks/notes (metadata), background process control for test suites
98
98
  # (background), and web fetch (http). See /plugin for the full tag list.
99
99
  tool_tags = ["core", "metadata", "background", "http"]
100
+ # Skills the session's model may load (listed under "### Skills" in the system
101
+ # prompt). Not set = the built-in skills; "none" = no skill tool; or a strict
102
+ # list. A [llm.*] profile's skills wins over this one for the session.
103
+ # skills = ["development-workflow"]
100
104
 
101
105
  [ui]
102
106
  # TUI layout (theme) — picks the chrome/layout:
@@ -180,6 +184,7 @@ driver = "ollama"
180
184
  base_url = "http://localhost:11434"
181
185
  model = "qwen3.6:35b-a3b-coding-nvfp4"
182
186
  num_ctx = 32768 # keep modest: local VRAM is the constraint
187
+ # skills = "none" # wins over [app].skills; agents on this profile inherit it
183
188
  reasoning_effort = "default"
184
189
  think = true # default; set false if the selected model rejects thinking
185
190
 
@@ -224,6 +229,7 @@ think = true # default; set false if the selected model r
224
229
  [agents.pm_spec]
225
230
  provider = "ollama_cloud"
226
231
  model = "glm-5.2:cloud"
232
+ # skills = ["development-workflow"] # wins over the provider profile's skills; [app] is never read
227
233
  temperature = 0.4
228
234
  max_output_tokens = 8192
229
235
  reasoning_effort = "high"
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "ayder-cli"
7
- version = "2.4.1"
7
+ version = "2.5.1"
8
8
  description = "AI agent for any LLMs"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -24,7 +24,7 @@ DEFAULT_BASELINE = REPO / "scripts" / "exception_baseline.txt"
24
24
 
25
25
  # Frozen census (§C10). A different number means the gate is looking at the
26
26
  # wrong tree, or the census moved without the plan being updated.
27
- EXPECTED_BROAD = 137
27
+ EXPECTED_BROAD = 134
28
28
  BRANCHING = (ast.If, ast.Try, ast.For, ast.While, ast.With, ast.Match)
29
29
  TERMINAL = (ast.Return, ast.Break, ast.Continue, ast.Pass)
30
30
 
@@ -203,13 +203,13 @@ FROZEN_CHAIN_SITES: dict[tuple[str, str, str, str], tuple[str, int]] = {
203
203
  ("log.py", "emit_event", "bind", "**"): ("Name(id='fields', ctx=Load())", 1),
204
204
  }
205
205
 
206
- # The 101 `exception=True` inputs are homogeneous, so they are governed as one
207
- # package-wide shape/count rule rather than 101 site identities - their per-site
206
+ # The 98 `exception=True` inputs are homogeneous, so they are governed as one
207
+ # package-wide shape/count rule rather than 98 site identities - their per-site
208
208
  # discipline is C10's.
209
- FROZEN_EXCEPTION_TRUE = 101
209
+ FROZEN_EXCEPTION_TRUE = 98
210
210
 
211
211
  # Live chain inputs, counted per method. Printed on every run.
212
- CHAIN_TALLY: dict[str, int] = {"bind": 6, "opt": 105, "patch": 0}
212
+ CHAIN_TALLY: dict[str, int] = {"bind": 6, "opt": 102, "patch": 0}
213
213
 
214
214
  # The reviewed composition of THE COMMITTED baseline, frozen by the Phase 5
215
215
  # census: 252 retained non-path + 22 paths + 2 deferred interpolated rows, plus
@@ -218,12 +218,12 @@ CHAIN_TALLY: dict[str, int] = {"bind": 6, "opt": 105, "patch": 0}
218
218
  # unchanged - so the composition is gated too. Caller-supplied baselines (the
219
219
  # gate's own synthetic fixtures) are exempt: this is a fact about one file.
220
220
  FROZEN_TALLY: dict[str, int] = {
221
- "R-name": 96,
221
+ "R-name": 99,
222
222
  "R-id": 40,
223
223
  "R-count": 90,
224
224
  "R-status": 27,
225
- "R-class": 10,
226
- "R-path": 24,
225
+ "R-class": 11,
226
+ "R-path": 25,
227
227
  # Both 5-04 deferrals are closed: the two asyncio rows now interpolate the
228
228
  # B2-prime normalized value, and the bridge's dynamic message is masked by
229
229
  # the prose sinks it reaches.
@@ -83,6 +83,7 @@
83
83
  {"class":"R-name","site":{"arg_index":"pos:0","expr":"name","message":"Uninstalled plugin '{}'","method":"info","path":"tools/plugin_manager.py","qualname":"uninstall_plugin"}}
84
84
  {"class":"R-name","site":{"arg_index":"pos:0","expr":"name","message":"cancel: agent='{}' \u2014 no running/queued instances","method":"debug","path":"agents/registry.py","qualname":"AgentRegistry.cancel"}}
85
85
  {"class":"R-name","site":{"arg_index":"pos:0","expr":"name","message":"cancel: agent='{}' cancelled {} instance(s): {}","method":"debug","path":"agents/registry.py","qualname":"AgentRegistry.cancel"}}
86
+ {"class":"R-name","site":{"arg_index":"pos:0","expr":"name","message":"skills lists {!r}, but no skill directory provides it","method":"warning","path":"core/skills.py","qualname":"build_scope"}}
86
87
  {"class":"R-status","site":{"arg_index":"pos:0","expr":"normalized","message":"Unhandled asyncio error: {}","method":"error","path":"diagnostics.py","qualname":"_handle_asyncio"}}
87
88
  {"class":"R-status","site":{"arg_index":"pos:0","expr":"normalized","message":"Unhandled asyncio exception: {}","method":"critical","path":"diagnostics.py","qualname":"_handle_asyncio"}}
88
89
  {"class":"R-count","site":{"arg_index":"pos:0","expr":"num_ctx","message":"Context budget: {} tokens (derived from num_ctx; max_context_tokens unset)","method":"info","path":"core/default_context_manager.py","qualname":"DefaultContextManager.__init__"}}
@@ -138,7 +139,9 @@
138
139
  {"class":"R-status","site":{"arg_index":"pos:0","expr":"self.config.chat_protocol","message":"Ollama chat_protocol={!r} is not recognized; forcing generic_xml fallback","method":"warning","path":"providers/impl/ollama.py","qualname":"OllamaProvider.stream_with_tools"}}
139
140
  {"class":"R-name","site":{"arg_index":"pos:0","expr":"self.config.model","message":"LLM returned empty response (possible connection drop). model={}, provider={}","method":"error","path":"loops/chat_loop.py","qualname":"ChatLoop.run"}}
140
141
  {"class":"R-status","site":{"arg_index":"pos:0","expr":"signal.Signals(signum).name","message":"Received signal {}; flushing logs","method":"warning","path":"diagnostics.py","qualname":"install_exception_hooks._chained_signal"}}
142
+ {"class":"R-name","site":{"arg_index":"pos:0","expr":"skill_dir.name","message":"Skill directory {!r} declares name {!r}; the directory name is used","method":"debug","path":"core/skills.py","qualname":"read_skill_info"}}
141
143
  {"class":"R-name","site":{"arg_index":"pos:0","expr":"source.repo","message":"Downloading '{}' at {}","method":"info","path":"tools/plugin_github.py","qualname":"download_plugin"}}
144
+ {"class":"R-path","site":{"arg_index":"pos:0","expr":"target","message":"Built-in skills were not synced to {} ({}); reading the packaged copy","method":"warning","path":"core/skills.py","qualname":"_sync_builtin_skills"}}
142
145
  {"class":"R-name","site":{"arg_index":"pos:0","expr":"tc.function.name","message":"Tool '{}' called with missing args {} ({} chars raw)","method":"warning","path":"loops/chat_loop.py","qualname":"ChatLoop._execute_tool_calls"}}
143
146
  {"class":"R-name","site":{"arg_index":"pos:0","expr":"tc_entry['function'].get('name', '?')","message":"Malformed tool arguments for '{}': {} chars \u2014 repairing before storing in history","method":"warning","path":"loops/chat_loop.py","qualname":"ChatLoop.run"}}
144
147
  {"class":"R-name","site":{"arg_index":"pos:0","expr":"tc_obj.function.name","message":"Tool execution cancelled: {}","method":"warning","path":"loops/chat_loop.py","qualname":"ChatLoop._execute_tool_calls._safe_exec"}}
@@ -160,6 +163,7 @@
160
163
  {"class":"R-status","site":{"arg_index":"pos:1","expr":"', '.join(valid)","message":"Unsupported driver (value_chars={}); must be one of: {}. Fix the driver in your [llm.<provider>] profile.","method":"error","path":"core/config.py","qualname":"Config.validate_driver"}}
161
164
  {"class":"R-name","site":{"arg_index":"pos:1","expr":"agent_name","message":"Agent panel could not show run {} of agent {}","method":"debug","path":"tui/commands.py","qualname":"handle_agent"}}
162
165
  {"class":"R-id","site":{"arg_index":"pos:1","expr":"commit_sha[:7]","message":"Downloading '{}' at {}","method":"info","path":"tools/plugin_github.py","qualname":"download_plugin"}}
166
+ {"class":"R-name","site":{"arg_index":"pos:1","expr":"declared","message":"Skill directory {!r} declares name {!r}; the directory name is used","method":"debug","path":"core/skills.py","qualname":"read_skill_info"}}
163
167
  {"class":"R-count","site":{"arg_index":"pos:1","expr":"delay","message":"Provider stream failed ({}); retrying in {:.2f}s ({} attempts left)","method":"info","path":"providers/retry.py","qualname":"RetryingProvider.stream_with_tools"}}
164
168
  {"class":"R-status","site":{"arg_index":"pos:1","expr":"driver.mode.value","message":"Ollama driver={} mode={} for {!r}","method":"info","path":"providers/impl/ollama.py","qualname":"OllamaProvider.stream_with_tools"}}
165
169
  {"class":"R-status","site":{"arg_index":"pos:1","expr":"driver.mode.value","message":"{} ({}) failed mid-stream (error_type={}); transparently retrying with {} ({})","method":"info","path":"providers/impl/ollama.py","qualname":"OllamaProvider.stream_with_tools"}}
@@ -222,6 +226,7 @@
222
226
  {"class":"R-name","site":{"arg_index":"pos:1","expr":"tc.name","message":"Tool call id reused by a different tool ({} then {}); calls would merge","method":"warning","path":"loops/chat_loop.py","qualname":"ChatLoop.run"}}
223
227
  {"class":"R-status","site":{"arg_index":"pos:1","expr":"think","message":"Ollama model {!r} rejected think={!r}; retrying with think=False","method":"info","path":"providers/impl/ollama.py","qualname":"OllamaProvider._stream_in_content"}}
224
228
  {"class":"R-status","site":{"arg_index":"pos:1","expr":"think","message":"Ollama model {!r} rejected think={!r}; retrying with think=False","method":"info","path":"providers/impl/ollama.py","qualname":"OllamaProvider._stream_native"}}
229
+ {"class":"R-class","site":{"arg_index":"pos:1","expr":"type(exc).__name__","message":"Built-in skills were not synced to {} ({}); reading the packaged copy","method":"warning","path":"core/skills.py","qualname":"_sync_builtin_skills"}}
225
230
  {"class":"R-class","site":{"arg_index":"pos:1","expr":"type(exc).__name__","message":"Provider retry budget exhausted after {} attempts; raising {}","method":"warning","path":"providers/retry.py","qualname":"RetryingProvider.stream_with_tools"}}
226
231
  {"class":"R-class","site":{"arg_index":"pos:1","expr":"type(exc).__name__","message":"Unreadable context slot at {}: {}","method":"warning","path":"tools/builtins/context.py","qualname":"_scan_context_dir"}}
227
232
  {"class":"R-name","site":{"arg_index":"pos:2","expr":"', '.join(discovered_modules)","message":"Auto-discovered {} tool definitions from {} modules: {}","method":"info","path":"tools/definition.py","qualname":"_discover_definitions"}}
@@ -1,9 +1,10 @@
1
1
  """AgentConfig — Pydantic model for agent definitions."""
2
2
 
3
- from typing import Any
3
+ from typing import Any, Literal
4
4
 
5
- from pydantic import BaseModel, ConfigDict, model_validator
5
+ from pydantic import BaseModel, ConfigDict, field_validator, model_validator
6
6
 
7
+ from ayder_cli.core.config import _coerce_skills_setting
7
8
  from ayder_cli.core.reasoning import ReasoningEffort, ThinkOption
8
9
 
9
10
 
@@ -32,6 +33,13 @@ class AgentConfig(BaseModel):
32
33
  max_output_tokens: int | None = None
33
34
  think: ThinkOption = None
34
35
  reasoning_effort: ReasoningEffort = None
36
+ # None: the provider profile's setting; "none" or a list: see Config.skills.
37
+ skills: list[str] | Literal["none"] | None = None
38
+
39
+ @field_validator("skills", mode="before")
40
+ @classmethod
41
+ def _validate_skills(cls, v: Any) -> Any:
42
+ return _coerce_skills_setting(v)
35
43
 
36
44
  @model_validator(mode="before")
37
45
  @classmethod
@@ -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
  )
@@ -6,7 +6,10 @@ eliminating the duplicate `_build_services()` / `AyderApp.__init__()` wiring.
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
+ import re
9
10
  from dataclasses import dataclass, field
11
+ from datetime import datetime
12
+ from pathlib import Path
10
13
  from typing import TYPE_CHECKING, Any
11
14
 
12
15
  from ayder_cli.core.config import Config, load_config, load_config_for_provider
@@ -15,14 +18,15 @@ from ayder_cli.core.context_manager_factory import context_manager_factory
15
18
 
16
19
  if TYPE_CHECKING:
17
20
  from ayder_cli.agents.config import AgentConfig
18
- from ayder_cli.core.context import ProjectContext
21
+ from ayder_cli.core.context import ProjectContext, new_scratch_dir
22
+ from ayder_cli.core.skills import build_scope
19
23
  from ayder_cli.providers import AIProvider, provider_orchestrator
20
24
  from ayder_cli.providers.retry import RetryConfig, RetryingProvider
21
25
  from ayder_cli.tools.registry import ToolRegistry, create_default_registry
22
26
  from ayder_cli.process_manager import ProcessManager
23
27
  from ayder_cli.prompts import (
28
+ build_environment_prompt,
24
29
  get_system_prompt,
25
- PROJECT_STRUCTURE_MACRO_TEMPLATE,
26
30
  )
27
31
  from ayder_cli.log import get_logger
28
32
 
@@ -40,6 +44,26 @@ class RuntimeComponents:
40
44
  tool_registry: ToolRegistry
41
45
  system_prompt: str
42
46
  context_manager: Any = field(default=None) # ContextManagerProtocol
47
+ environment_prompt: str = "" # frozen for the session; reused by TUI rebuilds
48
+
49
+
50
+ def apply_skill_setting(
51
+ tool_registry: ToolRegistry,
52
+ project_ctx: ProjectContext,
53
+ setting: Any,
54
+ messages: list[dict] | None = None,
55
+ ) -> None:
56
+ """Scope the registry's skills; hide the skill tool for "none", show it otherwise.
57
+
58
+ Called at runtime construction and again on a provider switch, where
59
+ ``messages`` is the live history (ChatLoop binds it only once).
60
+ """
61
+ tool_registry.skill_scope = build_scope(Path(project_ctx.root), setting)
62
+ tool_registry.skill_scope.messages = messages
63
+ if setting == "none":
64
+ tool_registry.excluded_tools.add("skill")
65
+ else:
66
+ tool_registry.excluded_tools.discard("skill")
43
67
 
44
68
 
45
69
  def create_runtime(
@@ -60,7 +84,7 @@ def create_runtime(
60
84
  (e.g. "AGENTIC" for `ayder-cli --agent`). See prompts.get_system_prompt.
61
85
  system_prompt_override: When set, use this text as the system-prompt base
62
86
  instead of prompts.get_system_prompt (ayder --system-prompt FILE). Tool
63
- prompts and the project-structure macro are still appended.
87
+ prompts are still appended.
64
88
 
65
89
  Returns:
66
90
  RuntimeComponents with all dependencies wired.
@@ -75,6 +99,9 @@ def create_runtime(
75
99
 
76
100
  llm_provider: AIProvider = provider_orchestrator.create(cfg)
77
101
  project_ctx = ProjectContext(project_root)
102
+ scratch_dir = new_scratch_dir(project_ctx.root)
103
+ if scratch_dir is not None:
104
+ project_ctx.scratch_dir = scratch_dir.resolve()
78
105
  process_manager = ProcessManager(max_processes=cfg.max_background_processes)
79
106
 
80
107
  # Create context manager before registry so tools can receive it via DI.
@@ -84,24 +111,19 @@ def create_runtime(
84
111
  process_manager=process_manager,
85
112
  context_manager=context_mgr,
86
113
  )
87
-
88
- try:
89
- structure = tool_registry.execute("get_project_structure", {"max_depth": 3})
90
- macro = PROJECT_STRUCTURE_MACRO_TEMPLATE.format(project_structure=structure)
91
- except Exception: # noqa: BLE001 - tool boundary: the project-structure macro is optional, so runtime construction continues without it
92
- logger.opt(exception=True).warning(
93
- "Project-structure macro unavailable; continuing without it"
94
- )
95
- macro = ""
114
+ apply_skill_setting(tool_registry, project_ctx, cfg.session_skills())
96
115
 
97
116
  # Format the final prompt (protocol injection now handled dynamically by chat_loop and protocols)
98
117
  if system_prompt_override is not None:
99
118
  base_prompt = system_prompt_override
100
119
  else:
101
120
  base_prompt = get_system_prompt(cfg.prompt)
121
+ environment_prompt = build_environment_prompt(
122
+ project_ctx.root, datetime.now().astimezone(), project_ctx.scratch_dir
123
+ )
102
124
  tool_tags = frozenset(cfg.tool_tags) if cfg.tool_tags else None
103
125
  tool_prompts = tool_registry.get_system_prompts(tags=tool_tags)
104
- system_prompt = base_prompt + tool_prompts + macro
126
+ system_prompt = base_prompt + environment_prompt + tool_prompts
105
127
 
106
128
  # Freeze system prompt after tool schemas are known.
107
129
  tool_schemas = tool_registry.get_schemas(tags=tool_tags)
@@ -117,6 +139,7 @@ def create_runtime(
117
139
  tool_registry=tool_registry,
118
140
  system_prompt=system_prompt,
119
141
  context_manager=context_mgr,
142
+ environment_prompt=environment_prompt,
120
143
  )
121
144
 
122
145
 
@@ -196,6 +219,9 @@ def create_agent_runtime(
196
219
  process_manager=process_manager,
197
220
  context_manager=context_mgr,
198
221
  )
222
+ # An agent reads its own setting, then its provider profile's; never [app].
223
+ skills_setting = agent_config.skills if agent_config.skills is not None else cfg.profile_skills
224
+ apply_skill_setting(tool_registry, project_ctx, skills_setting)
199
225
 
200
226
  # 5. Build agent system prompt
201
227
  identity_prefix = (
@@ -217,7 +243,19 @@ def create_agent_runtime(
217
243
  )
218
244
  tool_tags = frozenset(cfg.tool_tags) if cfg.tool_tags else None
219
245
  tool_prompts = tool_registry.get_system_prompts(tags=tool_tags)
220
- system_prompt = identity_prefix + agent_config.system_prompt + tool_prompts + deliverable_directive
246
+ # Each run gets its own directory inside the session's scratch directory,
247
+ # which the shared ProjectContext already admits.
248
+ agent_scratch = None
249
+ if project_ctx.scratch_dir is not None:
250
+ label = "agent-" + re.sub(r"[^A-Za-z0-9_-]", "-", agent_config.name)
251
+ agent_scratch = new_scratch_dir(project_ctx.root, parent=project_ctx.scratch_dir, label=label)
252
+ environment_prompt = build_environment_prompt(
253
+ project_ctx.root, datetime.now().astimezone(), agent_scratch
254
+ )
255
+ system_prompt = (
256
+ identity_prefix + agent_config.system_prompt + environment_prompt
257
+ + tool_prompts + deliverable_directive
258
+ )
221
259
 
222
260
  # Freeze agent system prompt after tool schemas are known.
223
261
  tool_schemas = tool_registry.get_schemas(tags=tool_tags)