drydock-cli 3.1.8__tar.gz → 3.1.9__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.8/drydock_cli.egg-info → drydock_cli-3.1.9}/PKG-INFO +14 -1
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/README.md +13 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/cli.py +6 -2
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/config.py +37 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/tui/app.py +9 -4
- {drydock_cli-3.1.8 → drydock_cli-3.1.9/drydock_cli.egg-info}/PKG-INFO +14 -1
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/pyproject.toml +1 -1
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_config.py +36 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/LICENSE +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/NOTICE +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/__init__.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/__main__.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/advisor.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/agent.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/bash_safety.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/budget.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/builtin_skills/__init__.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/builtin_skills/document-canvas.md +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/builtin_skills/fiar-assess.md +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/builtin_skills/fiar-cap.md +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/builtin_skills/fiar-evidence.md +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/builtin_skills/fiar-readiness.md +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/builtin_skills/ml-data.md +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/builtin_skills/ml-debug.md +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/builtin_skills/ml-finetune.md +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/builtin_skills/ml-metrics.md +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/builtin_skills/ml-rl.md +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/builtin_skills/ml-train.md +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/builtin_skills/nist-ai-rmf.md +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/builtin_skills/nist-csf.md +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/builtin_skills/rmf-categorize.md +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/builtin_skills/rmf-control.md +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/builtin_skills/rmf-poam.md +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/builtin_skills/rmf-review.md +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/builtin_skills/stig-assess.md +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/builtin_skills/stig-remediate.md +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/cci.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/compaction.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/detect.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/doccanvas.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/events.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/extract.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/fiar.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/gittools.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/graphrag.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/guards.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/loop_detect.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/mcp.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/phases.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/poam.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/progress.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/providers.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/ratchet.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/recipes.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/recovery.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/resume.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/rmf.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/rmf_graph.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/skills.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/stig.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/subagents.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/suggest.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/task_state.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/tool_policy.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/tool_registry.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/tool_result.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/tool_select.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/tool_validate.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/tools/__init__.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/trajectory.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/tui/__init__.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/tui/approval.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/tui/messages.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/tui/widgets.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/tuning.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/verification.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock/web.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock_cli.egg-info/SOURCES.txt +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock_cli.egg-info/dependency_links.txt +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock_cli.egg-info/entry_points.txt +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock_cli.egg-info/requires.txt +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/drydock_cli.egg-info/top_level.txt +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/setup.cfg +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_advisor.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_approval.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_back_command.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_bash_background.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_bash_binary_output.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_bash_crossplatform.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_bash_output_bounding.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_bash_process_group.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_bash_safety.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_bash_sanitize.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_bash_shell.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_bash_stdin.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_bash_stop_partial.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_bash_timeout_network.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_bash_timeout_param.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_budget.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_cci.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_cli_agents.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_compact_command.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_compaction.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_config_migration.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_context_limit_config.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_context_limit_issue25.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_criteria_coverage.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_cycling_detection.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_degenerate_argument.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_detect.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_dispatch.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_doccanvas.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_e2e_connected.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_edit_replace_all.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_effort_governor.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_empty_response.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_events.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_extract.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_failure_loop.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_fiar.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_first_run_setup.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_gittools.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_glob_edit_edges.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_graphify_example.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_graphrag.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_graphrag_quoted_path.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_graphrag_sqlite.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_grep_and_read_robust.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_guards_and_tools.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_hallucinated_tools.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_leaked_tool_call.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_loop_detect.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_mcp.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_model_registry.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_oneshot_unreachable.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_overthink_interrupt.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_phases.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_plan_autocontinue.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_poam.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_progress.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_providers_unreachable.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_ratchet.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_read_index.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_recipes.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_recovery.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_recovery_config.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_recovery_integration.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_repeated_outcome.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_repetition_interrupt.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_resume_events.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_resume_restore.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_resume_snapshot.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_rmf.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_rmf_graph.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_rmf_stig_graph.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_rolling_plan.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_runaway_repetition.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_screenshot.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_server_probe.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_skills.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_sqlite_events.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_stall_retry.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_stig.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_stop.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_streaming_newlines.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_subagent.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_subagents.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_suggest.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_system_prompt_help.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_task_state.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_timeline.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_todo.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_tool_arg_coercion.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_tool_arg_coercion_more.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_tool_arg_parsing.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_tool_canonical.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_tool_policy.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_tool_result.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_tool_select.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_tool_validate.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_tools_undo.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_trajectory.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_tui.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_tuning.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_verification_gate.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_viewimage.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_vision_input.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_web_tools.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_windows_shell.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_worker_subagent.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/tests/test_write_content_coerce.py +0 -0
- {drydock_cli-3.1.8 → drydock_cli-3.1.9}/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.9
|
|
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
|
|
@@ -447,6 +447,19 @@ commands to do the work, showing each as a collapsible tool card.
|
|
|
447
447
|
It honors `AGENTS.md` / `DRYDOCK.md` in the working directory for project
|
|
448
448
|
conventions.
|
|
449
449
|
|
|
450
|
+
### Custom system prompt
|
|
451
|
+
|
|
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.
|
|
462
|
+
|
|
450
463
|
## Safety
|
|
451
464
|
|
|
452
465
|
Two tiers, plus advisory guards — all designed so legitimate work is never
|
|
@@ -423,6 +423,19 @@ commands to do the work, showing each as a collapsible tool card.
|
|
|
423
423
|
It honors `AGENTS.md` / `DRYDOCK.md` in the working directory for project
|
|
424
424
|
conventions.
|
|
425
425
|
|
|
426
|
+
### Custom system prompt
|
|
427
|
+
|
|
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.
|
|
438
|
+
|
|
426
439
|
## Safety
|
|
427
440
|
|
|
428
441
|
Two tiers, plus advisory guards — all designed so legitimate work is never
|
|
@@ -13,6 +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
17
|
from drydock.agent import AgentState, run, TextChunk, ToolStart, ToolEnd, TurnDone
|
|
17
18
|
|
|
18
19
|
|
|
@@ -71,7 +72,7 @@ def print_colored(text: str, color: str = "") -> None:
|
|
|
71
72
|
|
|
72
73
|
def run_interactive(config: dict) -> None:
|
|
73
74
|
"""Interactive REPL mode."""
|
|
74
|
-
system = SYSTEM_PROMPT + load_project_instructions()
|
|
75
|
+
system = SYSTEM_PROMPT + load_user_system_prompt(config) + load_project_instructions()
|
|
75
76
|
state = AgentState()
|
|
76
77
|
|
|
77
78
|
print_colored(f"⚓ DryDock v{__version__} · {config['model']}", "cyan")
|
|
@@ -118,7 +119,7 @@ def run_oneshot(prompt: str, config: dict) -> None:
|
|
|
118
119
|
"""One-shot mode: run a single prompt and exit."""
|
|
119
120
|
from drydock.providers import LLMUnreachable
|
|
120
121
|
|
|
121
|
-
system = SYSTEM_PROMPT + load_project_instructions()
|
|
122
|
+
system = SYSTEM_PROMPT + load_user_system_prompt(config) + load_project_instructions()
|
|
122
123
|
state = AgentState()
|
|
123
124
|
|
|
124
125
|
try:
|
|
@@ -435,6 +436,9 @@ def main():
|
|
|
435
436
|
# greeting into a runaway build. The TUI reads this from config; CLI modes
|
|
436
437
|
# call load_project_instructions directly (see run_interactive/run_oneshot).
|
|
437
438
|
config["project_instructions"] = load_project_instructions()
|
|
439
|
+
# The user's custom system prompt (~/.drydock/system_prompt.md or the
|
|
440
|
+
# `system_prompt` config key) — standing instructions the TUI injects every turn.
|
|
441
|
+
config["user_system_prompt"] = load_user_system_prompt(config)
|
|
438
442
|
|
|
439
443
|
# Connect any configured MCP servers and register their tools so the model
|
|
440
444
|
# can call them like native tools. Failures are skipped (never block start);
|
|
@@ -106,6 +106,11 @@ DEFAULTS: dict[str, object] = {
|
|
|
106
106
|
# (falls back to `model`). Manage with `/model add|default|remove`.
|
|
107
107
|
"models": [],
|
|
108
108
|
"default_model": "",
|
|
109
|
+
# A custom system prompt injected into EVERY turn as the user's standing
|
|
110
|
+
# instructions (unlike a per-project AGENTS.md, which is framed as optional
|
|
111
|
+
# background). Two sources, file wins: the file ~/.drydock/system_prompt.md,
|
|
112
|
+
# or this inline key. Empty = nothing added. Capped at 8000 chars.
|
|
113
|
+
"system_prompt": "",
|
|
109
114
|
}
|
|
110
115
|
|
|
111
116
|
|
|
@@ -113,6 +118,38 @@ def default_config_path() -> Path:
|
|
|
113
118
|
return Path.home() / ".drydock" / "config.toml"
|
|
114
119
|
|
|
115
120
|
|
|
121
|
+
def system_prompt_path() -> Path:
|
|
122
|
+
"""User's global custom system-prompt file."""
|
|
123
|
+
return Path.home() / ".drydock" / "system_prompt.md"
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def load_user_system_prompt(config: dict | None = None) -> str:
|
|
127
|
+
"""The user's custom system prompt, injected every turn as standing orders.
|
|
128
|
+
|
|
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.
|
|
132
|
+
"""
|
|
133
|
+
text = ""
|
|
134
|
+
try:
|
|
135
|
+
p = system_prompt_path()
|
|
136
|
+
if p.exists():
|
|
137
|
+
text = p.read_text()
|
|
138
|
+
except OSError:
|
|
139
|
+
text = ""
|
|
140
|
+
if not text and config:
|
|
141
|
+
text = str(config.get("system_prompt", "") or "")
|
|
142
|
+
text = text.strip()
|
|
143
|
+
if not text:
|
|
144
|
+
return ""
|
|
145
|
+
return (
|
|
146
|
+
"\n\n## Custom instructions (from the user's configuration)\n\n"
|
|
147
|
+
"The user has set these standing instructions; follow them throughout "
|
|
148
|
+
"the session in addition to the guidance above.\n\n"
|
|
149
|
+
f"{text[:8000]}"
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
|
|
116
153
|
# ── Model registry ────────────────────────────────────────────────────────
|
|
117
154
|
# A model entry is {"name", "base_url", "provider"}. Kept in cfg["models"];
|
|
118
155
|
# cfg["default_model"] names the launch default. These helpers keep the list
|
|
@@ -341,10 +341,15 @@ class DrydockApp(App):
|
|
|
341
341
|
return "deny"
|
|
342
342
|
|
|
343
343
|
def _build_system(self, model: str | None) -> str:
|
|
344
|
-
#
|
|
345
|
-
#
|
|
346
|
-
#
|
|
347
|
-
|
|
344
|
+
# base (model-specific) + the user's custom system prompt (standing orders
|
|
345
|
+
# from ~/.drydock/system_prompt.md or the `system_prompt` config key) + a
|
|
346
|
+
# per-project AGENTS.md/DRYDOCK.md as background context. cli.main() loads
|
|
347
|
+
# both into config; drydock never auto-creates either file.
|
|
348
|
+
return (
|
|
349
|
+
system_prompt_for_model(model)
|
|
350
|
+
+ self.config.get("user_system_prompt", "")
|
|
351
|
+
+ self.config.get("project_instructions", "")
|
|
352
|
+
)
|
|
348
353
|
|
|
349
354
|
# ── layout ────────────────────────────────────────────────────────────
|
|
350
355
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: drydock-cli
|
|
3
|
-
Version: 3.1.
|
|
3
|
+
Version: 3.1.9
|
|
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
|
|
@@ -447,6 +447,19 @@ commands to do the work, showing each as a collapsible tool card.
|
|
|
447
447
|
It honors `AGENTS.md` / `DRYDOCK.md` in the working directory for project
|
|
448
448
|
conventions.
|
|
449
449
|
|
|
450
|
+
### Custom system prompt
|
|
451
|
+
|
|
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.
|
|
462
|
+
|
|
450
463
|
## Safety
|
|
451
464
|
|
|
452
465
|
Two tiers, plus advisory guards — all designed so legitimate work is never
|
|
@@ -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.9"
|
|
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"
|
|
@@ -89,3 +89,39 @@ def test_save_drops_runtime_only_keys(tmp_path):
|
|
|
89
89
|
assert "cwd" not in written
|
|
90
90
|
assert written["context_limit"] == 999
|
|
91
91
|
assert written["model"] == "g"
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# ── custom system prompt (~/.drydock/system_prompt.md or the `system_prompt` key) ──
|
|
95
|
+
|
|
96
|
+
def test_user_system_prompt_empty_by_default(monkeypatch, tmp_path):
|
|
97
|
+
monkeypatch.setattr(cfg.Path, "home", staticmethod(lambda: tmp_path))
|
|
98
|
+
assert cfg.load_user_system_prompt({}) == ""
|
|
99
|
+
assert cfg.load_user_system_prompt({"system_prompt": ""}) == ""
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def test_user_system_prompt_inline_key(monkeypatch, tmp_path):
|
|
103
|
+
monkeypatch.setattr(cfg.Path, "home", staticmethod(lambda: tmp_path))
|
|
104
|
+
out = cfg.load_user_system_prompt({"system_prompt": "Always answer in French."})
|
|
105
|
+
assert "Always answer in French." in out
|
|
106
|
+
assert "Custom instructions" in out
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def test_user_system_prompt_file_wins_over_inline(monkeypatch, tmp_path):
|
|
110
|
+
d = tmp_path / ".drydock"
|
|
111
|
+
d.mkdir()
|
|
112
|
+
(d / "system_prompt.md").write_text("FILE WINS")
|
|
113
|
+
monkeypatch.setattr(cfg.Path, "home", staticmethod(lambda: tmp_path))
|
|
114
|
+
out = cfg.load_user_system_prompt({"system_prompt": "inline loses"})
|
|
115
|
+
assert "FILE WINS" in out
|
|
116
|
+
assert "inline loses" not in out
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def test_user_system_prompt_capped_at_8000(monkeypatch, tmp_path):
|
|
120
|
+
monkeypatch.setattr(cfg.Path, "home", staticmethod(lambda: tmp_path))
|
|
121
|
+
out = cfg.load_user_system_prompt({"system_prompt": "x" * 20000})
|
|
122
|
+
assert out.count("x") == 8000
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def test_system_prompt_key_in_defaults():
|
|
126
|
+
assert "system_prompt" in cfg.DEFAULTS
|
|
127
|
+
assert cfg.DEFAULTS["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
|
|
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
|