feat: a command a model describes reads as its description on its row, the command in its body

Merged
DA
7d ago
+372-49

Summary

Dean asked whether tool calls commonly carry plain-English descriptions now, and said "Let's do it." Claude Code's Bash tool requires a short description ("Run tests", "List files in current directory") and shows it in place of the command. Cursor does the same with its own summaries. This PR does it for commands, the one call that needs it. File reads, edits, and searches already read as a verb and a subject.

Model side

  • apps/web/server/hosted/command-description.ts (new) defines the field once: an optional description beside command, described to the model as "What the command is for, in plain English for the developer reading along: 3 to 8 words, sentence case, no trailing period…". It also holds the one instruction line.
  • eve's bash takes the field without a fork. Luke already wraps eve's bash in coder-host/shell.ts (bashStartingIn, which starts every command in the checkout). The wrapper now overrides inputSchema with { command, description? } and still hands eve's execute only the command, so behaviour is unchanged. eve's own schema is additionalProperties: false, so the override is what lets the field through. The coding agent and its worker both use this tool.
  • The brain's run_in_repository schema gains the same optional field. Before this, its read refused unknown keys, so a described call would have answered not-run. The description is never handed to the sandbox.
  • One line asking for it ("Give every command a description…") is added to the coding agent's instructions, the coder worker's, the planning model's run_in_repository bullet, and the planning worker's.
  • Goldens: no prompt goldens exist in the repo. What the model is shown is now pinned as two new JSON Schema goldens, recorded under LUKE_UPDATE_FIXTURES=1: apps/web/fixtures/json-schema/run-in-repository-tool-input.json and coder-bash-tool-input.json. They are new files, not diffs. Each is command plus the optional description, with additionalProperties: false. Note that adding the field changes the tool-definition bytes, so each provider's prompt cache misses once on the first turn after deploy. That is the expected cost of any schema change.

Desktop

  • When a command's input has a description, its row reads the description alone, as words (not mono and with no "Ran"). This matches Claude Code and Cursor. The command moves into the opened body as today's $ command block, followed by its output. With no description (older rows, or another harness), the row is unchanged: "Ran ls -la". A blank description counts as none.
  • One shared decision, turn-rows.ts's callLine, draws this for both the coding agent's tab (tool-call-model.ts) and the Work tab (work-model.ts, which reads it from the call's input JSON). The two tabs cannot drift.
  • Transcript copy includes both. Concise: - Run the unit tests: \pnpm test`. Full: Run the unit tests: `pnpm test`` with the command fenced and the output under it. The agent tab's hover card previews the description alone, as the row does.
  • Find (#2156) matches both: the description is the row's text, and the command is in the fold, which Find already draws while its bar is open.
  • Session replay: the description is ordinary row text, so the existing masking covers it. Nothing new is stored, because the description is part of the saved tool input.

Tests

  • transcript-blocks.test.ts: on both the Work tab and an agent's tab, a described command's row reads exactly the description, with no mono span. It opens onto $ command and its output. The existing test still holds for undescribed commands ("Ran ls src"). This test fails without the change.
  • tool-call-model.test.ts: description goes to the row and the command to the body; with no description, or only blanks, the row is today's.
  • transcript-copy.test.ts: the concise and full copy and the latest-activity preview for a described command.
  • repository-shell.test.ts: a call with a description runs exactly the command, and the description never reaches the sandbox. This fails without the change, because the input used to be refused.
  • coder-shell.test.ts: a described command runs as the command alone. The offered schema is pinned by golden.
  • coder-agent.test.ts and planning-instructions.test.ts: every model holding a shell is asked for the description field that its shell's schema actually declares.

Evidence

  • ./scripts/check.sh: exit 0.
  • macOS Electron verification (./scripts/verify.sh): not run. This was built in a Linux cloud workspace. CI could not verify the Mac UI. CI builds nothing for the Mac, so a Mac break would be caught at the release rehearsal on a tag. LUKE-159 is the manual verify.sh pass that stands in for it.

Visual evidence

These are not verify.sh captures. They show the real AgentTranscriptView rendered in headless Chrome at 2× over the app's built styles.css, with the colour scheme forced light and dark. Three described commands (one opened, showing its command and output) sit above an undescribed git status --short, which keeps today's "Ran" row.

LightDark
Described commands, lightDescribed commands, dark

🤖 Generated with Claude Code