drydock-cli 3.1.10__tar.gz → 3.1.12__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.
- {drydock_cli-3.1.10/drydock_cli.egg-info → drydock_cli-3.1.12}/PKG-INFO +19 -11
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/README.md +18 -10
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/cli.py +6 -3
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/config.py +55 -23
- {drydock_cli-3.1.10 → drydock_cli-3.1.12/drydock_cli.egg-info}/PKG-INFO +19 -11
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/pyproject.toml +1 -1
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_config.py +40 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/LICENSE +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/NOTICE +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/__init__.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/__main__.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/advisor.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/agent.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/bash_safety.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/budget.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/builtin_skills/__init__.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/builtin_skills/document-canvas.md +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/builtin_skills/fiar-assess.md +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/builtin_skills/fiar-cap.md +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/builtin_skills/fiar-evidence.md +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/builtin_skills/fiar-readiness.md +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/builtin_skills/ml-data.md +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/builtin_skills/ml-debug.md +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/builtin_skills/ml-finetune.md +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/builtin_skills/ml-metrics.md +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/builtin_skills/ml-rl.md +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/builtin_skills/ml-train.md +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/builtin_skills/nist-ai-rmf.md +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/builtin_skills/nist-csf.md +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/builtin_skills/rmf-categorize.md +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/builtin_skills/rmf-control.md +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/builtin_skills/rmf-poam.md +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/builtin_skills/rmf-review.md +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/builtin_skills/stig-assess.md +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/builtin_skills/stig-remediate.md +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/cci.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/compaction.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/detect.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/doccanvas.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/events.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/extract.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/fiar.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/gittools.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/graphrag.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/guards.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/loop_detect.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/mcp.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/phases.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/poam.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/progress.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/providers.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/ratchet.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/recipes.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/recovery.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/resume.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/rmf.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/rmf_graph.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/skills.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/stig.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/subagents.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/suggest.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/task_state.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/tool_policy.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/tool_registry.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/tool_result.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/tool_select.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/tool_validate.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/tools/__init__.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/trajectory.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/tui/__init__.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/tui/app.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/tui/approval.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/tui/messages.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/tui/widgets.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/tuning.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/verification.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock/web.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock_cli.egg-info/SOURCES.txt +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock_cli.egg-info/dependency_links.txt +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock_cli.egg-info/entry_points.txt +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock_cli.egg-info/requires.txt +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/drydock_cli.egg-info/top_level.txt +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/setup.cfg +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_advisor.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_approval.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_back_command.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_bash_background.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_bash_binary_output.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_bash_crossplatform.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_bash_output_bounding.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_bash_process_group.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_bash_safety.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_bash_sanitize.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_bash_shell.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_bash_stdin.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_bash_stop_partial.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_bash_timeout_network.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_bash_timeout_param.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_budget.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_cci.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_cli_agents.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_compact_command.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_compaction.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_config_migration.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_context_limit_config.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_context_limit_issue25.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_criteria_coverage.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_cycling_detection.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_degenerate_argument.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_detect.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_dispatch.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_doccanvas.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_e2e_connected.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_edit_replace_all.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_effort_governor.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_empty_response.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_events.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_extract.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_failure_loop.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_fiar.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_first_run_setup.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_gittools.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_glob_edit_edges.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_graphify_example.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_graphrag.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_graphrag_quoted_path.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_graphrag_sqlite.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_grep_and_read_robust.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_guards_and_tools.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_hallucinated_tools.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_leaked_tool_call.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_loop_detect.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_mcp.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_model_registry.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_oneshot_unreachable.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_overthink_interrupt.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_phases.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_plan_autocontinue.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_poam.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_progress.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_providers_unreachable.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_ratchet.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_read_index.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_recipes.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_recovery.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_recovery_config.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_recovery_integration.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_repeated_outcome.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_repetition_interrupt.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_resume_events.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_resume_restore.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_resume_snapshot.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_rmf.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_rmf_graph.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_rmf_stig_graph.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_rolling_plan.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_runaway_repetition.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_screenshot.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_server_probe.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_skills.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_sqlite_events.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_stall_retry.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_stig.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_stop.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_streaming_newlines.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_subagent.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_subagents.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_suggest.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_system_prompt_help.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_task_state.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_timeline.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_todo.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_tool_arg_coercion.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_tool_arg_coercion_more.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_tool_arg_parsing.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_tool_canonical.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_tool_policy.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_tool_result.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_tool_select.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_tool_validate.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_tools_undo.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_trajectory.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_tui.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_tuning.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_verification_gate.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_viewimage.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_vision_input.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_web_tools.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_windows_shell.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_worker_subagent.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/tests/test_write_content_coerce.py +0 -0
- {drydock_cli-3.1.10 → drydock_cli-3.1.12}/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.
|
|
3
|
+
Version: 3.1.12
|
|
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,16 +450,24 @@ 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), edit
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
453
|
+
per-project `AGENTS.md`, which is framed as optional background), edit a
|
|
454
|
+
`system_prompt.md` file. Drydock creates a commented template for you, so you
|
|
455
|
+
never have to know where it lives — just open it and write your instructions.
|
|
456
|
+
It has no effect until you add text (the template is all comments, ignored).
|
|
457
|
+
|
|
458
|
+
Two scopes, most-specific wins:
|
|
459
|
+
|
|
460
|
+
- **Per-project** — `system_prompt.md` in the folder you launch drydock from.
|
|
461
|
+
Auto-created inside any **git repo** (so different projects get different
|
|
462
|
+
standing orders, and drydock never drops the file into non-project dirs).
|
|
463
|
+
- **Global** — `~/.drydock/system_prompt.md`. Auto-created on first run; applies
|
|
464
|
+
to every project. A per-project file **overrides** it.
|
|
465
|
+
- **Or the config key** — `system_prompt = "..."` in `~/.drydock/config.toml`
|
|
466
|
+
(lowest precedence).
|
|
467
|
+
|
|
468
|
+
Contents are capped at 8000 chars, injected after drydock's base prompt and
|
|
469
|
+
before any project `AGENTS.md`, and apply in both the TUI and CLI. Restart
|
|
470
|
+
drydock after editing.
|
|
463
471
|
|
|
464
472
|
## Safety
|
|
465
473
|
|
|
@@ -426,16 +426,24 @@ 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), edit
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
429
|
+
per-project `AGENTS.md`, which is framed as optional background), edit a
|
|
430
|
+
`system_prompt.md` file. Drydock creates a commented template for you, so you
|
|
431
|
+
never have to know where it lives — just open it and write your instructions.
|
|
432
|
+
It has no effect until you add text (the template is all comments, ignored).
|
|
433
|
+
|
|
434
|
+
Two scopes, most-specific wins:
|
|
435
|
+
|
|
436
|
+
- **Per-project** — `system_prompt.md` in the folder you launch drydock from.
|
|
437
|
+
Auto-created inside any **git repo** (so different projects get different
|
|
438
|
+
standing orders, and drydock never drops the file into non-project dirs).
|
|
439
|
+
- **Global** — `~/.drydock/system_prompt.md`. Auto-created on first run; applies
|
|
440
|
+
to every project. A per-project file **overrides** it.
|
|
441
|
+
- **Or the config key** — `system_prompt = "..."` in `~/.drydock/config.toml`
|
|
442
|
+
(lowest precedence).
|
|
443
|
+
|
|
444
|
+
Contents are capped at 8000 chars, injected after drydock's base prompt and
|
|
445
|
+
before any project `AGENTS.md`, and apply in both the TUI and CLI. Restart
|
|
446
|
+
drydock after editing.
|
|
439
447
|
|
|
440
448
|
## Safety
|
|
441
449
|
|
|
@@ -13,7 +13,7 @@ import sys
|
|
|
13
13
|
from pathlib import Path
|
|
14
14
|
|
|
15
15
|
from drydock import __version__
|
|
16
|
-
from drydock.config import load_user_system_prompt
|
|
16
|
+
from drydock.config import load_user_system_prompt, ensure_project_system_prompt
|
|
17
17
|
from drydock.agent import AgentState, run, TextChunk, ToolStart, ToolEnd, TurnDone
|
|
18
18
|
|
|
19
19
|
|
|
@@ -436,8 +436,11 @@ def main():
|
|
|
436
436
|
# greeting into a runaway build. The TUI reads this from config; CLI modes
|
|
437
437
|
# call load_project_instructions directly (see run_interactive/run_oneshot).
|
|
438
438
|
config["project_instructions"] = load_project_instructions()
|
|
439
|
-
#
|
|
440
|
-
#
|
|
439
|
+
# In a git project, drop a discoverable per-project prompt template at
|
|
440
|
+
# <project>/.drydock/system_prompt.md (inert until edited). Then load the
|
|
441
|
+
# effective custom prompt — project file OVERRIDES the global ~/.drydock one —
|
|
442
|
+
# as standing instructions the TUI/CLI inject every turn.
|
|
443
|
+
ensure_project_system_prompt()
|
|
441
444
|
config["user_system_prompt"] = load_user_system_prompt(config)
|
|
442
445
|
|
|
443
446
|
# Connect any configured MCP servers and register their tools so the model
|
|
@@ -120,14 +120,21 @@ def default_config_path() -> Path:
|
|
|
120
120
|
|
|
121
121
|
|
|
122
122
|
def system_prompt_path() -> Path:
|
|
123
|
-
"""User's
|
|
123
|
+
"""User's GLOBAL custom system-prompt file (applies to every project)."""
|
|
124
124
|
return Path.home() / ".drydock" / "system_prompt.md"
|
|
125
125
|
|
|
126
126
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
127
|
+
def project_system_prompt_path(cwd: Path | None = None) -> Path:
|
|
128
|
+
"""A PER-PROJECT custom system-prompt file: system_prompt.md in the folder
|
|
129
|
+
drydock was started from. Overrides the global one when present — different
|
|
130
|
+
projects, different orders."""
|
|
131
|
+
return (cwd or Path.cwd()) / "system_prompt.md"
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
# The template drydock drops so the file is always THERE and discoverable — the
|
|
135
|
+
# user never has to know the path or filename. It's ALL comments, so it has ZERO
|
|
136
|
+
# effect until the user writes real text below them (load_user_system_prompt
|
|
137
|
+
# strips <!-- --> blocks before use).
|
|
131
138
|
_SYSTEM_PROMPT_TEMPLATE = """\
|
|
132
139
|
<!--
|
|
133
140
|
Drydock custom system prompt.
|
|
@@ -139,6 +146,10 @@ _SYSTEM_PROMPT_TEMPLATE = """\
|
|
|
139
146
|
- Prefer the standard library; avoid adding new dependencies.
|
|
140
147
|
- State your plan in one sentence before making changes.
|
|
141
148
|
|
|
149
|
+
SCOPE: a system_prompt.md in a project's root folder is THAT PROJECT'S prompt;
|
|
150
|
+
the copy at ~/.drydock/system_prompt.md applies to every project. A project
|
|
151
|
+
file OVERRIDES the global one.
|
|
152
|
+
|
|
142
153
|
This template has NO effect until you add your own text below this comment.
|
|
143
154
|
Comment blocks like this one are ignored. Capped at 8000 characters.
|
|
144
155
|
Restart drydock after editing for changes to take effect.
|
|
@@ -151,13 +162,19 @@ def _strip_comments(text: str) -> str:
|
|
|
151
162
|
return re.sub(r"<!--.*?-->", "", text, flags=re.DOTALL)
|
|
152
163
|
|
|
153
164
|
|
|
154
|
-
def
|
|
155
|
-
"""
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
165
|
+
def _read_prompt_file(p: Path) -> str:
|
|
166
|
+
"""Comment-stripped, whitespace-trimmed contents of a prompt file, or ''."""
|
|
167
|
+
try:
|
|
168
|
+
if p.exists():
|
|
169
|
+
return _strip_comments(p.read_text()).strip()
|
|
170
|
+
except OSError:
|
|
171
|
+
pass
|
|
172
|
+
return ""
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _write_template(p: Path) -> None:
|
|
176
|
+
"""Write the commented template to p if absent. Never overwrites; never raises."""
|
|
159
177
|
try:
|
|
160
|
-
p = (config_dir / "system_prompt.md") if config_dir is not None else system_prompt_path()
|
|
161
178
|
if not p.exists():
|
|
162
179
|
p.parent.mkdir(parents=True, exist_ok=True)
|
|
163
180
|
p.write_text(_SYSTEM_PROMPT_TEMPLATE, encoding="utf-8")
|
|
@@ -165,21 +182,36 @@ def ensure_system_prompt_file(config_dir: Path | None = None) -> None:
|
|
|
165
182
|
pass
|
|
166
183
|
|
|
167
184
|
|
|
168
|
-
def
|
|
185
|
+
def ensure_system_prompt_file(config_dir: Path | None = None) -> None:
|
|
186
|
+
"""Create the GLOBAL <config_dir>/system_prompt.md template if absent (config_dir
|
|
187
|
+
defaults to ~/.drydock), so the feature is discoverable. Never overwrites."""
|
|
188
|
+
_write_template((config_dir / "system_prompt.md") if config_dir is not None else system_prompt_path())
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def ensure_project_system_prompt(cwd: Path | None = None) -> None:
|
|
192
|
+
"""Create system_prompt.md in the folder drydock was started from if absent —
|
|
193
|
+
but ONLY inside a git repo, so drydock never drops a system_prompt.md into
|
|
194
|
+
arbitrary directories (e.g. $HOME, /tmp). A real project you `git init`'d gets
|
|
195
|
+
a discoverable per-project prompt at its root; a throwaway cwd gets nothing.
|
|
196
|
+
Never raises."""
|
|
197
|
+
cwd = cwd or Path.cwd()
|
|
198
|
+
try:
|
|
199
|
+
if (cwd / ".git").exists(): # file OR dir — covers worktrees too
|
|
200
|
+
_write_template(project_system_prompt_path(cwd))
|
|
201
|
+
except OSError:
|
|
202
|
+
pass
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def load_user_system_prompt(config: dict | None = None, cwd: Path | None = None) -> str:
|
|
169
206
|
"""The user's custom system prompt, injected every turn as standing orders.
|
|
170
207
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
`system_prompt` config key.
|
|
174
|
-
chars. Returns '' when
|
|
208
|
+
Precedence (first with real content wins): the PER-PROJECT file
|
|
209
|
+
<project>/.drydock/system_prompt.md, then the GLOBAL ~/.drydock/system_prompt.md,
|
|
210
|
+
then the inline `system_prompt` config key. Comment blocks are stripped (so the
|
|
211
|
+
shipped template is inert). Capped at 8000 chars. Returns '' when none has real
|
|
212
|
+
content. Never raises.
|
|
175
213
|
"""
|
|
176
|
-
text =
|
|
177
|
-
try:
|
|
178
|
-
p = system_prompt_path()
|
|
179
|
-
if p.exists():
|
|
180
|
-
text = _strip_comments(p.read_text()).strip()
|
|
181
|
-
except OSError:
|
|
182
|
-
text = ""
|
|
214
|
+
text = _read_prompt_file(project_system_prompt_path(cwd)) or _read_prompt_file(system_prompt_path())
|
|
183
215
|
if not text and config:
|
|
184
216
|
text = str(config.get("system_prompt", "") or "").strip()
|
|
185
217
|
if not text:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: drydock-cli
|
|
3
|
-
Version: 3.1.
|
|
3
|
+
Version: 3.1.12
|
|
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,16 +450,24 @@ 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), edit
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
453
|
+
per-project `AGENTS.md`, which is framed as optional background), edit a
|
|
454
|
+
`system_prompt.md` file. Drydock creates a commented template for you, so you
|
|
455
|
+
never have to know where it lives — just open it and write your instructions.
|
|
456
|
+
It has no effect until you add text (the template is all comments, ignored).
|
|
457
|
+
|
|
458
|
+
Two scopes, most-specific wins:
|
|
459
|
+
|
|
460
|
+
- **Per-project** — `system_prompt.md` in the folder you launch drydock from.
|
|
461
|
+
Auto-created inside any **git repo** (so different projects get different
|
|
462
|
+
standing orders, and drydock never drops the file into non-project dirs).
|
|
463
|
+
- **Global** — `~/.drydock/system_prompt.md`. Auto-created on first run; applies
|
|
464
|
+
to every project. A per-project file **overrides** it.
|
|
465
|
+
- **Or the config key** — `system_prompt = "..."` in `~/.drydock/config.toml`
|
|
466
|
+
(lowest precedence).
|
|
467
|
+
|
|
468
|
+
Contents are capped at 8000 chars, injected after drydock's base prompt and
|
|
469
|
+
before any project `AGENTS.md`, and apply in both the TUI and CLI. Restart
|
|
470
|
+
drydock after editing.
|
|
463
471
|
|
|
464
472
|
## Safety
|
|
465
473
|
|
|
@@ -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.
|
|
10
|
+
version = "3.1.12"
|
|
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"
|
|
@@ -159,3 +159,43 @@ def test_load_ignores_comment_only_file(monkeypatch, tmp_path):
|
|
|
159
159
|
(d / "system_prompt.md").write_text(cfg._SYSTEM_PROMPT_TEMPLATE)
|
|
160
160
|
monkeypatch.setattr(cfg.Path, "home", staticmethod(lambda: tmp_path))
|
|
161
161
|
assert cfg.load_user_system_prompt({}) == ""
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
# ── per-project system prompt (<project>/.drydock/system_prompt.md) ──
|
|
165
|
+
|
|
166
|
+
def test_project_prompt_overrides_global(monkeypatch, tmp_path):
|
|
167
|
+
home = tmp_path / "home"; (home / ".drydock").mkdir(parents=True)
|
|
168
|
+
(home / ".drydock" / "system_prompt.md").write_text("GLOBAL RULES")
|
|
169
|
+
monkeypatch.setattr(cfg.Path, "home", staticmethod(lambda: home))
|
|
170
|
+
proj = tmp_path / "proj"; proj.mkdir()
|
|
171
|
+
(proj / "system_prompt.md").write_text("PROJECT RULES")
|
|
172
|
+
out = cfg.load_user_system_prompt({}, cwd=proj)
|
|
173
|
+
assert "PROJECT RULES" in out
|
|
174
|
+
assert "GLOBAL RULES" not in out
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def test_global_used_when_no_project_file(monkeypatch, tmp_path):
|
|
178
|
+
home = tmp_path / "home"; (home / ".drydock").mkdir(parents=True)
|
|
179
|
+
(home / ".drydock" / "system_prompt.md").write_text("GLOBAL RULES")
|
|
180
|
+
monkeypatch.setattr(cfg.Path, "home", staticmethod(lambda: home))
|
|
181
|
+
proj = tmp_path / "proj"; proj.mkdir() # no project system_prompt.md
|
|
182
|
+
out = cfg.load_user_system_prompt({}, cwd=proj)
|
|
183
|
+
assert "GLOBAL RULES" in out
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def test_ensure_project_prompt_only_in_git_repo(tmp_path):
|
|
187
|
+
# git repo → template created at the project root
|
|
188
|
+
repo = tmp_path / "repo"; (repo / ".git").mkdir(parents=True)
|
|
189
|
+
cfg.ensure_project_system_prompt(repo)
|
|
190
|
+
assert (repo / "system_prompt.md").exists()
|
|
191
|
+
# non-git dir → nothing created (no litter)
|
|
192
|
+
plain = tmp_path / "plain"; plain.mkdir()
|
|
193
|
+
cfg.ensure_project_system_prompt(plain)
|
|
194
|
+
assert not (plain / "system_prompt.md").exists()
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def test_ensure_project_prompt_never_overwrites(tmp_path):
|
|
198
|
+
repo = tmp_path / "repo"; (repo / ".git").mkdir(parents=True)
|
|
199
|
+
(repo / "system_prompt.md").write_text("MINE")
|
|
200
|
+
cfg.ensure_project_system_prompt(repo)
|
|
201
|
+
assert (repo / "system_prompt.md").read_text() == "MINE"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|