docs(#2628): update bash tool descriptions, docs, and system prompt for the todo model (trim impl details for agent)

This commit is contained in:
damocles 2026-07-22 17:34:12 +02:00
commit 3188e50ab8
5 changed files with 67 additions and 70 deletions

View file

@ -125,7 +125,7 @@ fn render_bash_run(id: &str, resp: Result<DaemonResponse>) -> String {
/// immediately re-waiting on the same task.
const BASH_IDLE_WAIT_HINT: &str = "\n\nThe task is still running — your wait timed out before it \
finished. If you have other useful work, do that and check back later (the task keeps running, and \
a wake fires when it completes) rather than immediately re-waiting.";
it surfaces in your loose-ends when it completes) rather than immediately re-waiting.";
/// Turn a `DaemonResponse` from a `BashStatus` call into the string
/// claude sees as the tool result. When `waited` is set (the call
@ -154,7 +154,7 @@ fn render_bash_kill(resp: Result<DaemonResponse>) -> String {
let sig = payload["signal"].as_str().unwrap_or("SIGINT");
format!(
"task `{id}`: {sig} sent to its process group; it transitions to `killed` \
once the process exits and the usual completion wake fires."
once the process exits and then surfaces in your loose-ends."
)
} else {
format!("task `{id}` was pending — cancelled before it started.")
@ -180,17 +180,16 @@ struct BashRunArgs {
timeout_secs: Option<u64>,
/// Optional inline wait: `run` polls for up to `wait_seconds`
/// (capped at 30) before returning. When the task finishes within the
/// window the full status is returned immediately and no wake is fired;
/// when the timeout expires the task keeps running and the normal
/// `task started: id=<id>` response is returned. Defaults to 3s. Pass
/// `0` to disable inline waiting and always get the immediate response.
/// window the full status is returned immediately (nothing to handle
/// later); when the timeout expires the task keeps running and the
/// normal `task started: id=<id>` response is returned. Defaults to 3s.
/// Pass `0` to disable inline waiting and always get the immediate response.
#[serde(default = "default_wait")]
wait_seconds: Option<u64>,
/// Optional task name. When set it becomes the task id, so it appears
/// in the completion wake (`from: "bash-task-<name>"`), in `status`
/// lookups, and in the loose-ends list — handy for recognising a task
/// later instead of an opaque hex id. A name can be reused once its
/// previous task has finished; reusing a name whose task is still
/// in `status` lookups and your loose-ends list — handy for recognising
/// a task later instead of an opaque hex id. A name can be reused once
/// its previous task has finished; reusing a name whose task is still
/// running is rejected. Allowed chars: ASCII letters, digits, `.`,
/// `_`, `-` (max 64). Omit to get the auto-generated id.
#[serde(default)]
@ -237,21 +236,18 @@ struct BashMcp;
impl BashMcp {
#[tool(
description = "Run a shell command in the background. Returns a task ID immediately — \
do NOT wait inline. When the command finishes, the harness fires a wake with \
`from: \"bash-task-<id>\"` carrying the exit status plus a `Read(<path>)` \
pointer to the captured `.out`/`.err` files (not the output text itself \
read only what you need); handle it on a future turn. Use `status` to poll the task status within \
the same turn if needed. `timeout_secs` defaults to `None` (no timeout) \
task runs until natural exit; pass an explicit value to kill after N seconds. \
Pass `wait_seconds` (capped at 30) to wait inline for fast commands: when the \
task finishes within the window the full status is returned immediately and no \
wake is fired; when the timeout expires the task keeps running and the normal \
`task started: id=<id>` response is returned. `wait_seconds` defaults to 3; \
pass `wait_seconds: 0` to disable inline waiting and always get the immediate \
response. Pass `name` to label the task with a memorable id (used in the wake \
`from`, `status` lookups, and the loose-ends list) instead of an opaque hex id; \
a name is reusable once its prior task has finished, and rejected while one is \
still running."
do NOT wait inline. When the command finishes it surfaces as a todo in your \
loose-ends (the exit status plus a `Read(<path>)` pointer to the captured \
`.out`/`.err` files read only what you need); handle it on a future turn. Use \
`status` to poll within the same turn if needed. `timeout_secs` defaults to \
`None` (no timeout) task runs until natural exit; pass a value to kill after \
N seconds. Pass `wait_seconds` (capped at 30) to wait inline for fast commands: \
if the task finishes within the window you get the full status immediately \
(nothing to handle later); otherwise it keeps running and you get \
`task started: id=<id>`. Defaults to 3; pass `0` to disable inline waiting. \
Pass `name` to label the task with a memorable id (shown in `status` lookups \
and your loose-ends) instead of an opaque hex id; reusable once the prior task \
has finished, rejected while one is still running."
)]
async fn run(&self, Parameters(args): Parameters<BashRunArgs>) -> String {
let req = DaemonRequest::BashRun {
@ -297,8 +293,8 @@ impl BashMcp {
signalled, so a runaway child (cargo/nix/etc.) is stopped too, not just the shell. \
Fire-and-forget: sends the signal and returns without waiting. If a SIGINT'd task \
doesn't exit, call kill again with `force: true` to SIGKILL. A still-pending task \
is cancelled before it starts. The task ends as `killed` and fires the usual \
completion wake."
is cancelled before it starts. The task ends as `killed` and surfaces in your \
loose-ends like any completion."
)]
async fn kill(&self, Parameters(args): Parameters<BashKillArgs>) -> String {
let req = DaemonRequest::BashKill {