drydock-cli 3.1.9__tar.gz → 3.1.10__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 (192) hide show
  1. {drydock_cli-3.1.9/drydock_cli.egg-info → drydock_cli-3.1.10}/PKG-INFO +11 -10
  2. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/README.md +10 -9
  3. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/config.py +52 -6
  4. {drydock_cli-3.1.9 → drydock_cli-3.1.10/drydock_cli.egg-info}/PKG-INFO +11 -10
  5. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/pyproject.toml +1 -1
  6. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_config.py +34 -0
  7. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/LICENSE +0 -0
  8. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/NOTICE +0 -0
  9. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/__init__.py +0 -0
  10. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/__main__.py +0 -0
  11. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/advisor.py +0 -0
  12. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/agent.py +0 -0
  13. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/bash_safety.py +0 -0
  14. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/budget.py +0 -0
  15. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/builtin_skills/__init__.py +0 -0
  16. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/builtin_skills/document-canvas.md +0 -0
  17. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/builtin_skills/fiar-assess.md +0 -0
  18. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/builtin_skills/fiar-cap.md +0 -0
  19. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/builtin_skills/fiar-evidence.md +0 -0
  20. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/builtin_skills/fiar-readiness.md +0 -0
  21. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/builtin_skills/ml-data.md +0 -0
  22. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/builtin_skills/ml-debug.md +0 -0
  23. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/builtin_skills/ml-finetune.md +0 -0
  24. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/builtin_skills/ml-metrics.md +0 -0
  25. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/builtin_skills/ml-rl.md +0 -0
  26. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/builtin_skills/ml-train.md +0 -0
  27. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/builtin_skills/nist-ai-rmf.md +0 -0
  28. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/builtin_skills/nist-csf.md +0 -0
  29. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/builtin_skills/rmf-categorize.md +0 -0
  30. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/builtin_skills/rmf-control.md +0 -0
  31. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/builtin_skills/rmf-poam.md +0 -0
  32. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/builtin_skills/rmf-review.md +0 -0
  33. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/builtin_skills/stig-assess.md +0 -0
  34. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/builtin_skills/stig-remediate.md +0 -0
  35. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/cci.py +0 -0
  36. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/cli.py +0 -0
  37. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/compaction.py +0 -0
  38. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/detect.py +0 -0
  39. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/doccanvas.py +0 -0
  40. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/events.py +0 -0
  41. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/extract.py +0 -0
  42. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/fiar.py +0 -0
  43. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/gittools.py +0 -0
  44. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/graphrag.py +0 -0
  45. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/guards.py +0 -0
  46. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/loop_detect.py +0 -0
  47. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/mcp.py +0 -0
  48. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/phases.py +0 -0
  49. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/poam.py +0 -0
  50. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/progress.py +0 -0
  51. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/providers.py +0 -0
  52. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/ratchet.py +0 -0
  53. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/recipes.py +0 -0
  54. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/recovery.py +0 -0
  55. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/resume.py +0 -0
  56. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/rmf.py +0 -0
  57. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/rmf_graph.py +0 -0
  58. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/skills.py +0 -0
  59. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/stig.py +0 -0
  60. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/subagents.py +0 -0
  61. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/suggest.py +0 -0
  62. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/task_state.py +0 -0
  63. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/tool_policy.py +0 -0
  64. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/tool_registry.py +0 -0
  65. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/tool_result.py +0 -0
  66. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/tool_select.py +0 -0
  67. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/tool_validate.py +0 -0
  68. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/tools/__init__.py +0 -0
  69. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/trajectory.py +0 -0
  70. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/tui/__init__.py +0 -0
  71. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/tui/app.py +0 -0
  72. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/tui/approval.py +0 -0
  73. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/tui/messages.py +0 -0
  74. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/tui/widgets.py +0 -0
  75. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/tuning.py +0 -0
  76. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/verification.py +0 -0
  77. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock/web.py +0 -0
  78. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock_cli.egg-info/SOURCES.txt +0 -0
  79. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock_cli.egg-info/dependency_links.txt +0 -0
  80. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock_cli.egg-info/entry_points.txt +0 -0
  81. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock_cli.egg-info/requires.txt +0 -0
  82. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/drydock_cli.egg-info/top_level.txt +0 -0
  83. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/setup.cfg +0 -0
  84. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_advisor.py +0 -0
  85. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_approval.py +0 -0
  86. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_back_command.py +0 -0
  87. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_bash_background.py +0 -0
  88. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_bash_binary_output.py +0 -0
  89. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_bash_crossplatform.py +0 -0
  90. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_bash_output_bounding.py +0 -0
  91. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_bash_process_group.py +0 -0
  92. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_bash_safety.py +0 -0
  93. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_bash_sanitize.py +0 -0
  94. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_bash_shell.py +0 -0
  95. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_bash_stdin.py +0 -0
  96. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_bash_stop_partial.py +0 -0
  97. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_bash_timeout_network.py +0 -0
  98. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_bash_timeout_param.py +0 -0
  99. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_budget.py +0 -0
  100. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_cci.py +0 -0
  101. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_cli_agents.py +0 -0
  102. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_compact_command.py +0 -0
  103. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_compaction.py +0 -0
  104. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_config_migration.py +0 -0
  105. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_context_limit_config.py +0 -0
  106. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_context_limit_issue25.py +0 -0
  107. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_criteria_coverage.py +0 -0
  108. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_cycling_detection.py +0 -0
  109. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_degenerate_argument.py +0 -0
  110. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_detect.py +0 -0
  111. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_dispatch.py +0 -0
  112. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_doccanvas.py +0 -0
  113. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_e2e_connected.py +0 -0
  114. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_edit_replace_all.py +0 -0
  115. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_effort_governor.py +0 -0
  116. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_empty_response.py +0 -0
  117. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_events.py +0 -0
  118. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_extract.py +0 -0
  119. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_failure_loop.py +0 -0
  120. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_fiar.py +0 -0
  121. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_first_run_setup.py +0 -0
  122. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_gittools.py +0 -0
  123. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_glob_edit_edges.py +0 -0
  124. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_graphify_example.py +0 -0
  125. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_graphrag.py +0 -0
  126. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_graphrag_quoted_path.py +0 -0
  127. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_graphrag_sqlite.py +0 -0
  128. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_grep_and_read_robust.py +0 -0
  129. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_guards_and_tools.py +0 -0
  130. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_hallucinated_tools.py +0 -0
  131. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_leaked_tool_call.py +0 -0
  132. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_loop_detect.py +0 -0
  133. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_mcp.py +0 -0
  134. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_model_registry.py +0 -0
  135. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_oneshot_unreachable.py +0 -0
  136. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_overthink_interrupt.py +0 -0
  137. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_phases.py +0 -0
  138. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_plan_autocontinue.py +0 -0
  139. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_poam.py +0 -0
  140. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_progress.py +0 -0
  141. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_providers_unreachable.py +0 -0
  142. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_ratchet.py +0 -0
  143. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_read_index.py +0 -0
  144. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_recipes.py +0 -0
  145. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_recovery.py +0 -0
  146. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_recovery_config.py +0 -0
  147. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_recovery_integration.py +0 -0
  148. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_repeated_outcome.py +0 -0
  149. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_repetition_interrupt.py +0 -0
  150. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_resume_events.py +0 -0
  151. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_resume_restore.py +0 -0
  152. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_resume_snapshot.py +0 -0
  153. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_rmf.py +0 -0
  154. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_rmf_graph.py +0 -0
  155. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_rmf_stig_graph.py +0 -0
  156. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_rolling_plan.py +0 -0
  157. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_runaway_repetition.py +0 -0
  158. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_screenshot.py +0 -0
  159. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_server_probe.py +0 -0
  160. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_skills.py +0 -0
  161. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_sqlite_events.py +0 -0
  162. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_stall_retry.py +0 -0
  163. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_stig.py +0 -0
  164. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_stop.py +0 -0
  165. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_streaming_newlines.py +0 -0
  166. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_subagent.py +0 -0
  167. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_subagents.py +0 -0
  168. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_suggest.py +0 -0
  169. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_system_prompt_help.py +0 -0
  170. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_task_state.py +0 -0
  171. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_timeline.py +0 -0
  172. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_todo.py +0 -0
  173. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_tool_arg_coercion.py +0 -0
  174. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_tool_arg_coercion_more.py +0 -0
  175. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_tool_arg_parsing.py +0 -0
  176. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_tool_canonical.py +0 -0
  177. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_tool_policy.py +0 -0
  178. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_tool_result.py +0 -0
  179. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_tool_select.py +0 -0
  180. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_tool_validate.py +0 -0
  181. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_tools_undo.py +0 -0
  182. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_trajectory.py +0 -0
  183. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_tui.py +0 -0
  184. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_tuning.py +0 -0
  185. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_verification_gate.py +0 -0
  186. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_viewimage.py +0 -0
  187. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_vision_input.py +0 -0
  188. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_web_tools.py +0 -0
  189. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_windows_shell.py +0 -0
  190. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_worker_subagent.py +0 -0
  191. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_write_content_coerce.py +0 -0
  192. {drydock_cli-3.1.9 → drydock_cli-3.1.10}/tests/test_xccdf.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drydock-cli
3
- Version: 3.1.9
3
+ Version: 3.1.10
4
4
  Summary: Drydock — a local, provider-agnostic terminal coding agent for local LLMs
5
5
  Author: Frank Bobe III
6
6
  License-Expression: Apache-2.0
@@ -450,15 +450,16 @@ conventions.
450
450
  ### Custom system prompt
451
451
 
452
452
  For standing instructions applied on **every** turn (stronger than the
453
- per-project `AGENTS.md`, which is framed as optional background), set a custom
454
- system prompt via either:
455
-
456
- - a file: `~/.drydock/system_prompt.md` — write your instructions there, or
457
- - a config key in `~/.drydock/config.toml`: `system_prompt = "..."`.
458
-
459
- The file wins if both are set; contents are capped at 8000 chars. It's injected
460
- after drydock's base prompt and before any project `AGENTS.md`, and applies in
461
- both the TUI and CLI.
453
+ per-project `AGENTS.md`, which is framed as optional background), edit
454
+ **`~/.drydock/system_prompt.md`**. Drydock creates this file for you (a
455
+ commented template) on first run, so you never have to know where it lives —
456
+ just open it and write your instructions. It has no effect until you add text
457
+ (the template is all comments, which are ignored).
458
+
459
+ Prefer keeping it in the config file instead? Set `system_prompt = "..."` in
460
+ `~/.drydock/config.toml`. The `system_prompt.md` file wins if both are set;
461
+ contents are capped at 8000 chars, injected after drydock's base prompt and
462
+ before any project `AGENTS.md`, and apply in both the TUI and CLI.
462
463
 
463
464
  ## Safety
464
465
 
@@ -426,15 +426,16 @@ conventions.
426
426
  ### Custom system prompt
427
427
 
428
428
  For standing instructions applied on **every** turn (stronger than the
429
- per-project `AGENTS.md`, which is framed as optional background), set a custom
430
- system prompt via either:
431
-
432
- - a file: `~/.drydock/system_prompt.md` — write your instructions there, or
433
- - a config key in `~/.drydock/config.toml`: `system_prompt = "..."`.
434
-
435
- The file wins if both are set; contents are capped at 8000 chars. It's injected
436
- after drydock's base prompt and before any project `AGENTS.md`, and applies in
437
- both the TUI and CLI.
429
+ per-project `AGENTS.md`, which is framed as optional background), edit
430
+ **`~/.drydock/system_prompt.md`**. Drydock creates this file for you (a
431
+ commented template) on first run, so you never have to know where it lives —
432
+ just open it and write your instructions. It has no effect until you add text
433
+ (the template is all comments, which are ignored).
434
+
435
+ Prefer keeping it in the config file instead? Set `system_prompt = "..."` in
436
+ `~/.drydock/config.toml`. The `system_prompt.md` file wins if both are set;
437
+ contents are capped at 8000 chars, injected after drydock's base prompt and
438
+ before any project `AGENTS.md`, and apply in both the TUI and CLI.
438
439
 
439
440
  ## Safety
440
441
 
@@ -13,6 +13,7 @@ All logic original to Drydock.
13
13
  """
14
14
  from __future__ import annotations
15
15
 
16
+ import re
16
17
  import tomllib
17
18
  from pathlib import Path
18
19
 
@@ -123,23 +124,64 @@ def system_prompt_path() -> Path:
123
124
  return Path.home() / ".drydock" / "system_prompt.md"
124
125
 
125
126
 
127
+ # The template drydock drops at ~/.drydock/system_prompt.md so the file is always
128
+ # THERE and discoverable — the user never has to know the path or filename. It's
129
+ # ALL comments, so it has ZERO effect until the user writes real text below them
130
+ # (load_user_system_prompt strips <!-- --> blocks before use).
131
+ _SYSTEM_PROMPT_TEMPLATE = """\
132
+ <!--
133
+ Drydock custom system prompt.
134
+
135
+ Whatever you write in this file (OUTSIDE these comment blocks) is added to the
136
+ system prompt on EVERY turn, in both the TUI and CLI — your standing instructions.
137
+ Examples you might add below:
138
+ - Always run the test suite after editing code.
139
+ - Prefer the standard library; avoid adding new dependencies.
140
+ - State your plan in one sentence before making changes.
141
+
142
+ This template has NO effect until you add your own text below this comment.
143
+ Comment blocks like this one are ignored. Capped at 8000 characters.
144
+ Restart drydock after editing for changes to take effect.
145
+ -->
146
+ """
147
+
148
+
149
+ def _strip_comments(text: str) -> str:
150
+ """Drop HTML comment blocks so the shipped template is inert until edited."""
151
+ return re.sub(r"<!--.*?-->", "", text, flags=re.DOTALL)
152
+
153
+
154
+ def ensure_system_prompt_file(config_dir: Path | None = None) -> None:
155
+ """Create <config_dir>/system_prompt.md (the commented template) if it's absent,
156
+ so users discover the feature without knowing the path/name. `config_dir`
157
+ defaults to ~/.drydock. NEVER overwrites an existing file (can't clobber a real
158
+ prompt) and never raises."""
159
+ try:
160
+ p = (config_dir / "system_prompt.md") if config_dir is not None else system_prompt_path()
161
+ if not p.exists():
162
+ p.parent.mkdir(parents=True, exist_ok=True)
163
+ p.write_text(_SYSTEM_PROMPT_TEMPLATE, encoding="utf-8")
164
+ except OSError:
165
+ pass
166
+
167
+
126
168
  def load_user_system_prompt(config: dict | None = None) -> str:
127
169
  """The user's custom system prompt, injected every turn as standing orders.
128
170
 
129
- Source (first non-empty wins): the file ~/.drydock/system_prompt.md, then the
130
- inline `system_prompt` config key. Wrapped with a clear header and capped at
131
- 8000 chars. Returns '' when neither is set. Never raises.
171
+ Source (first non-empty wins): the file ~/.drydock/system_prompt.md (comment
172
+ blocks stripped, so the shipped template is inert), then the inline
173
+ `system_prompt` config key. Wrapped with a clear header and capped at 8000
174
+ chars. Returns '' when neither has real content. Never raises.
132
175
  """
133
176
  text = ""
134
177
  try:
135
178
  p = system_prompt_path()
136
179
  if p.exists():
137
- text = p.read_text()
180
+ text = _strip_comments(p.read_text()).strip()
138
181
  except OSError:
139
182
  text = ""
140
183
  if not text and config:
141
- text = str(config.get("system_prompt", "") or "")
142
- text = text.strip()
184
+ text = str(config.get("system_prompt", "") or "").strip()
143
185
  if not text:
144
186
  return ""
145
187
  return (
@@ -289,6 +331,10 @@ def resolve(cli_overrides: dict, path: Path | None = None) -> dict:
289
331
  has an editable v3 config with a visible endpoint.
290
332
  """
291
333
  path = path or default_config_path()
334
+ # Drop the discoverable custom-system-prompt template alongside config.toml so
335
+ # the user never has to know its path/name. Inert (all comments) until edited;
336
+ # never overwrites an existing file.
337
+ ensure_system_prompt_file(path.parent)
292
338
  if not path.exists():
293
339
  save_file(dict(DEFAULTS), path)
294
340
  file_cfg = {}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drydock-cli
3
- Version: 3.1.9
3
+ Version: 3.1.10
4
4
  Summary: Drydock — a local, provider-agnostic terminal coding agent for local LLMs
5
5
  Author: Frank Bobe III
6
6
  License-Expression: Apache-2.0
@@ -450,15 +450,16 @@ conventions.
450
450
  ### Custom system prompt
451
451
 
452
452
  For standing instructions applied on **every** turn (stronger than the
453
- per-project `AGENTS.md`, which is framed as optional background), set a custom
454
- system prompt via either:
455
-
456
- - a file: `~/.drydock/system_prompt.md` — write your instructions there, or
457
- - a config key in `~/.drydock/config.toml`: `system_prompt = "..."`.
458
-
459
- The file wins if both are set; contents are capped at 8000 chars. It's injected
460
- after drydock's base prompt and before any project `AGENTS.md`, and applies in
461
- both the TUI and CLI.
453
+ per-project `AGENTS.md`, which is framed as optional background), edit
454
+ **`~/.drydock/system_prompt.md`**. Drydock creates this file for you (a
455
+ commented template) on first run, so you never have to know where it lives —
456
+ just open it and write your instructions. It has no effect until you add text
457
+ (the template is all comments, which are ignored).
458
+
459
+ Prefer keeping it in the config file instead? Set `system_prompt = "..."` in
460
+ `~/.drydock/config.toml`. The `system_prompt.md` file wins if both are set;
461
+ contents are capped at 8000 chars, injected after drydock's base prompt and
462
+ before any project `AGENTS.md`, and apply in both the TUI and CLI.
462
463
 
463
464
  ## Safety
464
465
 
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
7
7
  # PyPI distribution name is drydock-cli (the established install name, continued
8
8
  # from the retired v2 fork); the import package + CLI command stay `drydock`.
9
9
  name = "drydock-cli"
10
- version = "3.1.9"
10
+ version = "3.1.10"
11
11
  description = "Drydock — a local, provider-agnostic terminal coding agent for local LLMs"
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.11"
@@ -125,3 +125,37 @@ def test_user_system_prompt_capped_at_8000(monkeypatch, tmp_path):
125
125
  def test_system_prompt_key_in_defaults():
126
126
  assert "system_prompt" in cfg.DEFAULTS
127
127
  assert cfg.DEFAULTS["system_prompt"] == ""
128
+
129
+
130
+ def test_resolve_creates_inert_system_prompt_template(tmp_path):
131
+ # resolve() drops the template next to config.toml, and it has NO effect until edited
132
+ cfgpath = tmp_path / "config.toml"
133
+ cfg.resolve({}, cfgpath)
134
+ tmpl = tmp_path / "system_prompt.md"
135
+ assert tmpl.exists(), "template should be auto-created"
136
+ assert "<!--" in tmpl.read_text()
137
+ # inert: all-comments template contributes nothing to the prompt
138
+ assert cfg._strip_comments(tmpl.read_text()).strip() == ""
139
+
140
+
141
+ def test_ensure_system_prompt_never_overwrites(tmp_path):
142
+ f = tmp_path / "system_prompt.md"
143
+ f.write_text("MY REAL PROMPT")
144
+ cfg.ensure_system_prompt_file(tmp_path)
145
+ assert f.read_text() == "MY REAL PROMPT"
146
+
147
+
148
+ def test_load_strips_comments_keeps_real_text(monkeypatch, tmp_path):
149
+ d = tmp_path / ".drydock"; d.mkdir()
150
+ (d / "system_prompt.md").write_text("<!-- ignore me -->\nReal instruction here.")
151
+ monkeypatch.setattr(cfg.Path, "home", staticmethod(lambda: tmp_path))
152
+ out = cfg.load_user_system_prompt({})
153
+ assert "Real instruction here." in out
154
+ assert "ignore me" not in out
155
+
156
+
157
+ def test_load_ignores_comment_only_file(monkeypatch, tmp_path):
158
+ d = tmp_path / ".drydock"; d.mkdir()
159
+ (d / "system_prompt.md").write_text(cfg._SYSTEM_PROMPT_TEMPLATE)
160
+ monkeypatch.setattr(cfg.Path, "home", staticmethod(lambda: tmp_path))
161
+ assert cfg.load_user_system_prompt({}) == ""
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes