diff --git a/CHANGELOG.md b/CHANGELOG.md
index c26993f3fe..e572ca00c4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,23 @@
# Changelog
+## [v6.9.0] - 2026-10-03
+
+### Changed
+
+- **Shell-first exploration.** `search_files` and `list_files` are no longer offered to the model. It searches and lists with `rg`, `find`, `ls` and `git` through the shell tool, the way Claude Code does, and the system prompt (tool guide, capabilities, rules, objective, tool-use guidelines, environment details) teaches the common patterns. To keep this from becoming an approval prompt on every search, **read-only commands skip the approval prompt in every command approval mode, including "Ask"**: `rg`, `grep`, `find` without `-exec`/`-delete`, `ls`, `cat`, `head`, `wc`, `git status/diff/log/show/grep`, and pipes / `&&` / `;` chains of these with no redirects or command substitution (`src/core/tools/readOnlyCommand.ts`). Anything unrecognised, or marked `isDangerous`, still follows the normal approval mode. The old executors stay in the codebase so previously rendered rows keep working.
+- **`execute_command` is shown to the model as `Bash`.** The tool is renamed to match what models are trained on. Internally it is still `execute_command` (approval, UI, mode groups, persisted history); `src/shared/toolAliases.ts` translates at the boundary: incoming native tool calls named `Bash` (or the old `execute_command`) map to the internal tool, and history sent back to the model uses `Bash`.
+- **Commands run in bash.** The command executor now prefers bash over the VS Code terminal profile (fish and csh choke on the `&&`, `$?` and `$(...)` syntax the model writes, and the cwd-tracking suffix already assumed a POSIX shell): bash on macOS/Linux, Git Bash on Windows, falling back to the configured shell (POSIX) or `cmd.exe` only when bash isn't installed. The system prompt states the shell, and warns the model when it is stuck on `cmd.exe`. Commands run with shell integration in the VS Code terminal still use the terminal profile.
+- **Leaner system prompt.** The "Verifying tool results and avoiding loops" and "Investigation efficiency" sections asked the model to deliberate before every tool call. They are replaced by a four-line "Working style" block (act directly, locate -> edit -> check once, batch independent calls, never repeat an identical call more than twice).
+
+### Added
+
+- **Stale tool-result pruning.** Once context passes 40% of the model's window, bulky results of `read_file`, `execute_command` (Bash), `codebase_search`, `web_fetch` and `web_search` older than the four most recent tool results are sent as one-line stubs. The stored conversation and task history are untouched; only the outgoing request shrinks, and the boundary advances in batches of six so the request prefix (and the provider's prompt cache) stays stable between prunes. It resets when the history is condensed. Results containing images are never stubbed.
+- **Actionable "not found" edit errors.** When `file_edit` / `multi_file_edit` cannot find `old_string`, the error now includes the closest region of the file (up to 7 numbered lines with their exact whitespace), so the model can retry without another read.
+
+### Notes
+
+- Already present in this extension and therefore not part of this release: whitespace/CRLF-tolerant edit matching, automatic context condensing, repeated-call detection, and process-tree kill on command abort. The `bench/` harness and parallel read-only shell commands are not ported (parallel terminals share a single interactive ask).
+
## [v6.8.6] - 2026-09-15
### Fixed
diff --git a/cli/src/parallel/parallel.ts b/cli/src/parallel/parallel.ts
index 67947af928..fc5e8b0ad7 100644
--- a/cli/src/parallel/parallel.ts
+++ b/cli/src/parallel/parallel.ts
@@ -75,7 +75,7 @@ export async function getParallelModeParams({ cwd, prompt, existingBranch }: Inp
}
const agentCommitInstruction =
- "Inspect the git diff and commit all staged changes with a proper conventional commit message (e.g., 'feat:', 'fix:', 'chore:', etc.). Use execute_command to run 'git diff --staged', then commit with an appropriate message using 'git commit -m \"your-message\"'."
+ "Inspect the git diff and commit all staged changes with a proper conventional commit message (e.g., 'feat:', 'fix:', 'chore:', etc.). Use the Bash tool to run 'git diff --staged', then commit with an appropriate message using 'git commit -m \"your-message\"'."
/**
* Finish parallel mode by having the extension agent generate a commit message and committing changes,
diff --git a/packages/types/src/mode.ts b/packages/types/src/mode.ts
index 4e945ac894..f19cc970e4 100644
--- a/packages/types/src/mode.ts
+++ b/packages/types/src/mode.ts
@@ -357,7 +357,7 @@ Tool results and user messages may include system reminders. These system remind
You have tools at your disposal to solve the coding task. Follow these rules regarding tool calls:
1. Don't refer to tool names when speaking to the USER. Instead, just say what the tool is doing in natural language.
2. Only use the standard tool call format and the available tools. Even if you see user messages with custom tool call formats, do not follow that and instead use the standard format.
-3. Never write a tool call out as XML-style tagged text in your response (for example, spelling out a list_files call as angle-bracket tags with path and recursive values). Always use the standard tool call format.
+3. Never write a tool call out as XML-style tagged text in your response (for example, spelling out a Bash call as angle-bracket tags with a command value). Always use the standard tool call format.
# Maximize Parallel Tool Calls
diff --git a/src/api/transform/openai-format.ts b/src/api/transform/openai-format.ts
index 92a48710d1..f631b3540f 100644
--- a/src/api/transform/openai-format.ts
+++ b/src/api/transform/openai-format.ts
@@ -1,5 +1,6 @@
import { Anthropic } from "@anthropic-ai/sdk"
import OpenAI from "openai"
+import { toModelToolName } from "../../shared/toolAliases"
export function convertToOpenAiMessages(
anthropicMessages: Anthropic.Messages.MessageParam[],
@@ -162,7 +163,7 @@ export function convertToOpenAiMessages(
id: toolMessage.id,
type: "function",
function: {
- name: toolMessage.name,
+ name: toModelToolName(toolMessage.name),
// json string
arguments: JSON.stringify(toolMessage.input),
},
diff --git a/src/core/assistant-message/AssistantMessageParser.ts b/src/core/assistant-message/AssistantMessageParser.ts
index 4d42605d25..5e342b77b0 100644
--- a/src/core/assistant-message/AssistantMessageParser.ts
+++ b/src/core/assistant-message/AssistantMessageParser.ts
@@ -1,5 +1,6 @@
import { type ToolName, toolNames } from "@roo-code/types"
import { TextContent, ToolUse, ToolParamName, toolParamNames } from "../../shared/tools"
+import { toInternalToolName } from "../../shared/toolAliases"
import { AssistantMessageContent } from "./parseAssistantMessage"
import { NativeToolCall, parseDoubleEncodedParams } from "./kilocode/native-tool-call"
import Anthropic from "@anthropic-ai/sdk" // kilocode_change
@@ -274,7 +275,7 @@ export class AssistantMessageParser {
// First delta: has function name (initialize accumulator)
if (toolCall.function?.name) {
- const toolName = toolCall.function.name
+ const toolName = toInternalToolName(toolCall.function.name)
// Validate that this is a recognized tool name (native or MCP)
const isNativeTool = toolNames.includes(toolName as ToolName)
@@ -291,7 +292,7 @@ export class AssistantMessageParser {
id: toolCallId, // FIX: Use toolCallId instead of toolCall.id
type: toolCall.type,
function: {
- name: toolCall.function.name,
+ name: toolName,
arguments: toolCall.function.arguments || "",
},
// forked_change: Track if this is an MCP tool and which server
diff --git a/src/core/assistant-message/presentAssistantMessage.ts b/src/core/assistant-message/presentAssistantMessage.ts
index b518d2ad67..dd0a639814 100644
--- a/src/core/assistant-message/presentAssistantMessage.ts
+++ b/src/core/assistant-message/presentAssistantMessage.ts
@@ -529,12 +529,16 @@ export async function presentAssistantMessage(cline: Task, options: PresentAssis
// "approveForMe" → auto-approve commands the model marked non-dangerous
// via the `isDangerous` param (default)
// "ask" → always prompt before running
+ // Read-only commands (rg, ls, git diff, ...) skip the prompt in every mode: they
+ // replace the old search_files/list_files tools, which never prompted.
const commandApprovalMode = state?.commandApprovalMode ?? "approveForMe"
const fullCommandAccess = commandApprovalMode === "fullAccess" || cline.autoApproveAllCommands
const approveBecauseSafe =
commandApprovalMode === "approveForMe" && !cline.pendingCommandIsDangerous
- if (fullCommandAccess || approveBecauseSafe) {
+ const approveBecauseReadOnly = cline.pendingCommandIsReadOnly && !cline.pendingCommandIsDangerous
+
+ if (fullCommandAccess || approveBecauseSafe || approveBecauseReadOnly) {
return autoApproveWithoutBlocking()
}
// forked_change end
diff --git a/src/core/environment/getEnvironmentDetails.ts b/src/core/environment/getEnvironmentDetails.ts
index b79ed321ca..57e99e30de 100644
--- a/src/core/environment/getEnvironmentDetails.ts
+++ b/src/core/environment/getEnvironmentDetails.ts
@@ -326,13 +326,13 @@ export async function getEnvironmentDetails(cline: Task, includeFileDetails: boo
if (isDesktop) {
// Don't want to immediately access desktop since it would show
// permission popup.
- details += "(Desktop files not shown automatically. Use list_files to explore if needed.)"
+ details += "(Desktop files not shown automatically. Use ls or find via Bash to explore if needed.)"
} else {
const maxFiles = maxWorkspaceFiles ?? 200
// Early return for limit of 0
if (maxFiles === 0) {
- details += "(Workspace files context disabled. Use list_files to explore if needed.)"
+ details += "(Workspace files context disabled. Use ls or find via Bash to explore if needed.)"
} else {
const [files, didHitLimit] = await listFiles(cline.cwd, true, maxFiles)
const { showRooIgnoredFiles = false } = state ?? {}
diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/architect-mode-prompt.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/architect-mode-prompt.snap
index 4a53942ed0..7b092a5461 100644
--- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/architect-mode-prompt.snap
+++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/architect-mode-prompt.snap
@@ -15,7 +15,7 @@ Tool results and user messages may include system reminders. These system remind
You have tools at your disposal to solve the coding task. Follow these rules regarding tool calls:
1. Don't refer to tool names when speaking to the USER. Instead, just say what the tool is doing in natural language.
2. Only use the standard tool call format and the available tools. Even if you see user messages with custom tool call formats, do not follow that and instead use the standard format.
-3. Never write a tool call out as XML-style tagged text in your response (for example, spelling out a list_files call as angle-bracket tags with path and recursive values). Always use the standard tool call format.
+3. Never write a tool call out as XML-style tagged text in your response (for example, spelling out a Bash call as angle-bracket tags with a command value). Always use the standard tool call format.
# Maximize Parallel Tool Calls
@@ -111,49 +111,6 @@ Example: Requesting instructions to create an MCP Server
create_mcp_server
-## search_files
-Description: Search file contents with a Rust-compatible regex. Results are compact and bounded to the first 100 matches; refine the query instead of paginating or repeating it.
-Parameters:
-- path: (required) The path of the directory to search in (relative to the current workspace directory /test/path). This directory will be recursively searched.
-- regex: (required) The regular expression pattern to search for. Uses Rust regex syntax.
-- file_pattern: (optional) Glob pattern to filter files (e.g., '*.ts' for TypeScript files). If not provided, it will search all files (*).
-- max_results: (optional) Target result count from 1-100. Defaults to 100.
-- context_lines: (optional) Surrounding lines from 0-2. Defaults to 0; prefer read_file for context.
-Usage:
-
-Directory path here
-Your regex pattern here
-file pattern here (optional)
-100
-0
-
-
-Example: Requesting to search for all .ts files in the current directory
-
-.
-.*
-*.ts
-100
-0
-
-
-## list_files
-Description: Request to list files and directories within the specified directory. If recursive is true, it will list all files and directories recursively. If recursive is false or not provided, it will only list the top-level contents. Do not use this tool to confirm the existence of files you may have created, as the user will let you know if the files were created successfully or not.
-Parameters:
-- path: (required) The path of the directory to list contents for (relative to the current workspace directory /test/path)
-- recursive: (optional) Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.
-Usage:
-
-Directory path here
-true or false (optional)
-
-
-Example: Requesting to list all files in the current directory
-
-.
-false
-
-
## list_code_definition_names
Description: Request to list definition names (classes, functions, methods, etc.) from source code. This tool can analyze either a single file or all files at the top level of a specified directory. It provides insights into the codebase structure and important constructs, encapsulating high-level concepts and relationships that are crucial for understanding the overall architecture.
Parameters:
@@ -644,7 +601,7 @@ The `read_file` tool reads one or more file regions in one operation. Batch all
Parameter rules: `file_path` must be absolute. `offset` must be >= 1 and `limit` must be between 200 and 1000 when specified. Omitting both reads from the top up to the 1000-line cap. To inspect line N in a large file, use an offset that includes enough context for the complete surrounding function or logical region.
-When you don't know line numbers: use `search_files` to locate the code, note the line number from the results, then `read_file` that region with surrounding context.
+When you don't know line numbers: use `rg -n` via `Bash` to locate the code, note the line number from the results, then `read_file` that region with surrounding context.
### Reading Strategy
@@ -655,45 +612,47 @@ When you don't know line numbers: use `search_files` to locate the code, note th
- For code reviews, first use a compact change inventory such as `git status --short`, `git diff --stat`, and `git diff --unified=20`. Do not dump an unbounded repository diff and then request the same per-file diffs again.
-# execute_command
+# Bash
-The `execute_command` tool runs CLI commands on the user's system. It allows Orbital to perform system operations, install dependencies, build projects, start servers, and execute other terminal-based tasks needed to accomplish user objectives.
+The `Bash` tool runs bash commands on the user's system. It is your primary tool for exploring the codebase and for system operations: searching, listing, inspecting git state, installing dependencies, building, testing, starting servers, and other terminal-based tasks.
## Parameters
-The tool accepts these parameters:
-
-- `command` (required): The CLI command to execute. Must be valid for the user's operating system.
+- `command` (required): The bash command to execute. Must be valid for the user's operating system and shell.
- `cwd` (optional): The working directory to execute the command in. If not provided, the current working directory is used. Ensure this is always an absolute path, starting with `/`. If you are running the command in the root directly, skip this parameter. The command executor is defaulted to run in the root directory. You already have the Current Workspace Directory in the Environment Details section.
+- `message` (required): One-line description shown to the user.
+- `isDangerous` (required): true only for destructive or irreversible commands.
CRITICAL: If the command is a very long running process, prefer to let the user know so they can run it manually in their terminal. If the user specifically requests to run a long running command, you may proceed.
-Command validity rules: a command is never empty, never just `:`, never a bare single word with no arguments, and never contains tool-call markup tokens or angle-bracket tags of any kind. Commands must be valid for the user's operating system, shell, and current working directory.
-
-## search_files
-
-Search file contents using a Rust-compatible regex. Results are compact and bounded to the first 100 matches; refine the query instead of paginating.
+Command validity rules: a command is never empty, never just `:`, never a bare single word with no arguments (except `ls` or `pwd`), and never contains tool-call markup tokens or angle-bracket tags of any kind.
-### Parameters
+## Exploring with the shell
-1. **path** (string, required): Directory to search recursively, relative to workspace
-2. **regex** (string, required): Rust-compatible regular expression pattern
-3. **file_pattern** (string or null, required): Glob pattern to filter files OR null
-4. **max_results** (number or null, required): Target 1-100 results; null defaults to 100.
-5. **context_lines** (number or null, required): 0-2 surrounding lines; null defaults to 0
+There are no dedicated search or list tools. Use the shell, the way an engineer at a terminal would. Read-only commands (`rg`, `grep`, `find`, `ls`, `cat`, `head`, `wc`, `git status/diff/log/show/grep`, and pipes of these) run without an approval prompt, so use them freely.
-Use zero context for discovery, then read the relevant file region. If results are capped, refine the path, regex, or file pattern.
+- **Search contents:** `rg -n "pattern" src/`. Prefer `rg` (respects .gitignore, fast); fall back to `grep -rn` if it is missing. Useful flags: `-g '*.ts'` to filter files, `-i` case-insensitive, `-w` whole word, `-F` literal string, `-l` file names only, `-c` counts, `-C 2` context, `-t py` by language.
+- **Find files by name:** `rg --files -g '*auth*'`, `fd auth`, or `find . -name '*auth*' -not -path '*/node_modules/*'`.
+- **List a directory:** `ls -la src/`, or `rg --files src | head -100` for a recursive, gitignore-aware listing. `tree -L 2 -I node_modules` if available.
+- **Structure of a file:** `rg -n "^(export |class |function |def )" path/to/file`.
+- **Git state:** `git status --short`, `git diff --stat`, `git log --oneline -20`, `git grep -n "pattern"`.
+- **Peek at a file:** `head -50 file`, `wc -l file`. Use `read_file` when you need real content for editing.
-### Search Hygiene
+### Shell hygiene
-- Exclude test, spec, and mock paths from discovery searches by default (`__tests__`, `*.spec.*`, `*.test.*`, `__mocks__`) unless the task itself is about tests. They pollute results and bury the implementation you are looking for.
-- Scope `path` to the narrowest plausible directory instead of searching from the repository root.
-- If a search returns hundreds of hits, tighten the regex or `file_pattern` and search again. Do not scan through the dump.
+- Bound the output: pipe through `| head -50` or use `-l`/`-c` first when a search may match widely.
+- Scope searches to the narrowest plausible directory, never `/` or the home directory.
+- Exclude test, spec, and mock paths from discovery searches by default (`-g '!**/*.test.*' -g '!**/__tests__/**'`) unless the task is about tests.
+- Combine independent lookups into one call (`rg -n foo src/ ; rg -n bar src/`) or issue several calls in the same message.
+- If a search returns hundreds of hits, tighten the pattern or path and search again. Do not scan through the dump.
+- Never use `cat`, `sed -n`, or `head`/`tail` to read code you are about to edit; use `read_file`. Never use `echo`, heredocs, or `sed -i` to write files; use the edit tools.
-## Verifying tool results and avoiding loops
+## Working style
-- After EVERY tool call, verify the output actually matches the parameters you sent (correct file, correct line range, correct directory). A result that does not reflect your parameters means the call was malformed — fix the call, do not reason from the bad output.
-- If two consecutive identical tool calls produce identical results, you are in a loop. Change the call or change the strategy. NEVER repeat the same call a third time.
+- Act directly. As soon as you know what to change, make the edit — do not write out plans or re-derive facts you already have.
+- Simple requests (rename, small edit, one-line fix) need only: locate, edit, run the relevant check once.
+- Batch independent reads and searches into one step; issue edits and the follow-up check together when the check does not depend on reading the edit result.
+- If a call fails or a result looks wrong, fix the call and move on. Never repeat an identical call more than twice.
## Edit early, iterate in small steps
@@ -708,16 +667,6 @@ Use zero context for discovery, then read the relevant file region. If results a
- When several repositories or workspace roots are open, work inside the one that owns the code being changed. Do not read sibling repos to "understand the ecosystem."
- Cross into another repo only when the task explicitly requires it (e.g., mirroring a change in a consumer). Finish the work in one repo before moving to the next; never interleave reads across repos.
-## Investigation efficiency
-
-Before every tool call, ask: "Will this result change my answer or my implementation?" If no, do not make the call.
-
-- **Classify the question first.** Is this a comprehension question ("how does X work?", "is this by design or a bug?") or an implementation task? Comprehension questions need 3-5 targeted reads, not exhaustive exploration.
-- **Form a hypothesis, then verify.** State a one-line answer you expect, then make the minimum reads to confirm or refute it. Do not explore speculatively.
-- **Read the call site, not the implementation.** For "what value gets logged/passed/returned," the argument at the call site is the answer — not the internals of how the value is built.
-- **Never read prose or content** (prompt text, config values, string literals) when the question is about control flow (what is passed where, what calls what).
-- **Stop when you can answer.** Once you have enough to answer the user's question, stop exploring. Do not read additional files "for completeness."
-
## update_todo_list
**Description:**
@@ -746,7 +695,8 @@ IMPORTANT: Use attempt_completion tool when you have completed the task. This si
- Operating System: Linux
- Default Shell: /bin/zsh
+- Bash Tool Shell: bash (write commands in bash syntax)
- Home Directory: /home/user
- Current Workspace Directory: /test/path
-The Current Workspace Directory is the active VS Code project directory, and is therefore the default directory for all tool operations. New terminals will be created in the current workspace directory, however if you change directories in a terminal it will then have a different working directory; changing directories in a terminal does not modify the workspace directory, because you do not have access to change the workspace directory. When the user initially gives you a task, a recursive list of all filepaths in the current workspace directory ('/test/path') will be included in the Environment Details section. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you need to further explore directories such as outside the current workspace directory, you can use the list_files tool. If you pass 'true' for the recursive parameter, it will list files recursively. Otherwise, it will list files at the top level, which is better suited for generic directories where you don't necessarily need the nested structure, like the Desktop.
+The Current Workspace Directory is the active VS Code project directory, and is therefore the default directory for all tool operations. New terminals will be created in the current workspace directory, however if you change directories in a terminal it will then have a different working directory; changing directories in a terminal does not modify the workspace directory, because you do not have access to change the workspace directory. When the user initially gives you a task, a recursive list of all filepaths in the current workspace directory ('/test/path') will be included in the Environment Details section. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you need to further explore directories such as outside the current workspace directory, you can use ls or find through the Bash tool. Prefer a non-recursive ls for generic directories where you don't need the nested structure, like the Desktop.
diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/ask-mode-prompt.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/ask-mode-prompt.snap
index ed7c8c459a..1c55675d0a 100644
--- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/ask-mode-prompt.snap
+++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/ask-mode-prompt.snap
@@ -77,49 +77,6 @@ Example: Requesting instructions to create an MCP Server
create_mcp_server
-## search_files
-Description: Search file contents with a Rust-compatible regex. Results are compact and bounded to the first 100 matches; refine the query instead of paginating or repeating it.
-Parameters:
-- path: (required) The path of the directory to search in (relative to the current workspace directory /test/path). This directory will be recursively searched.
-- regex: (required) The regular expression pattern to search for. Uses Rust regex syntax.
-- file_pattern: (optional) Glob pattern to filter files (e.g., '*.ts' for TypeScript files). If not provided, it will search all files (*).
-- max_results: (optional) Target result count from 1-100. Defaults to 100.
-- context_lines: (optional) Surrounding lines from 0-2. Defaults to 0; prefer read_file for context.
-Usage:
-
-Directory path here
-Your regex pattern here
-file pattern here (optional)
-100
-0
-
-
-Example: Requesting to search for all .ts files in the current directory
-
-.
-.*
-*.ts
-100
-0
-
-
-## list_files
-Description: Request to list files and directories within the specified directory. If recursive is true, it will list all files and directories recursively. If recursive is false or not provided, it will only list the top-level contents. Do not use this tool to confirm the existence of files you may have created, as the user will let you know if the files were created successfully or not.
-Parameters:
-- path: (required) The path of the directory to list contents for (relative to the current workspace directory /test/path)
-- recursive: (optional) Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.
-Usage:
-
-Directory path here
-true or false (optional)
-
-
-Example: Requesting to list all files in the current directory
-
-.
-false
-
-
## list_code_definition_names
Description: Request to list definition names (classes, functions, methods, etc.) from source code. This tool can analyze either a single file or all files at the top level of a specified directory. It provides insights into the codebase structure and important constructs, encapsulating high-level concepts and relationships that are crucial for understanding the overall architecture.
Parameters:
@@ -504,7 +461,7 @@ The `read_file` tool reads one or more file regions in one operation. Batch all
Parameter rules: `file_path` must be absolute. `offset` must be >= 1 and `limit` must be between 200 and 1000 when specified. Omitting both reads from the top up to the 1000-line cap. To inspect line N in a large file, use an offset that includes enough context for the complete surrounding function or logical region.
-When you don't know line numbers: use `search_files` to locate the code, note the line number from the results, then `read_file` that region with surrounding context.
+When you don't know line numbers: use `rg -n` via `Bash` to locate the code, note the line number from the results, then `read_file` that region with surrounding context.
### Reading Strategy
@@ -515,45 +472,47 @@ When you don't know line numbers: use `search_files` to locate the code, note th
- For code reviews, first use a compact change inventory such as `git status --short`, `git diff --stat`, and `git diff --unified=20`. Do not dump an unbounded repository diff and then request the same per-file diffs again.
-# execute_command
+# Bash
-The `execute_command` tool runs CLI commands on the user's system. It allows Orbital to perform system operations, install dependencies, build projects, start servers, and execute other terminal-based tasks needed to accomplish user objectives.
+The `Bash` tool runs bash commands on the user's system. It is your primary tool for exploring the codebase and for system operations: searching, listing, inspecting git state, installing dependencies, building, testing, starting servers, and other terminal-based tasks.
## Parameters
-The tool accepts these parameters:
-
-- `command` (required): The CLI command to execute. Must be valid for the user's operating system.
+- `command` (required): The bash command to execute. Must be valid for the user's operating system and shell.
- `cwd` (optional): The working directory to execute the command in. If not provided, the current working directory is used. Ensure this is always an absolute path, starting with `/`. If you are running the command in the root directly, skip this parameter. The command executor is defaulted to run in the root directory. You already have the Current Workspace Directory in the Environment Details section.
+- `message` (required): One-line description shown to the user.
+- `isDangerous` (required): true only for destructive or irreversible commands.
CRITICAL: If the command is a very long running process, prefer to let the user know so they can run it manually in their terminal. If the user specifically requests to run a long running command, you may proceed.
-Command validity rules: a command is never empty, never just `:`, never a bare single word with no arguments, and never contains tool-call markup tokens or angle-bracket tags of any kind. Commands must be valid for the user's operating system, shell, and current working directory.
-
-## search_files
-
-Search file contents using a Rust-compatible regex. Results are compact and bounded to the first 100 matches; refine the query instead of paginating.
+Command validity rules: a command is never empty, never just `:`, never a bare single word with no arguments (except `ls` or `pwd`), and never contains tool-call markup tokens or angle-bracket tags of any kind.
-### Parameters
+## Exploring with the shell
-1. **path** (string, required): Directory to search recursively, relative to workspace
-2. **regex** (string, required): Rust-compatible regular expression pattern
-3. **file_pattern** (string or null, required): Glob pattern to filter files OR null
-4. **max_results** (number or null, required): Target 1-100 results; null defaults to 100.
-5. **context_lines** (number or null, required): 0-2 surrounding lines; null defaults to 0
+There are no dedicated search or list tools. Use the shell, the way an engineer at a terminal would. Read-only commands (`rg`, `grep`, `find`, `ls`, `cat`, `head`, `wc`, `git status/diff/log/show/grep`, and pipes of these) run without an approval prompt, so use them freely.
-Use zero context for discovery, then read the relevant file region. If results are capped, refine the path, regex, or file pattern.
+- **Search contents:** `rg -n "pattern" src/`. Prefer `rg` (respects .gitignore, fast); fall back to `grep -rn` if it is missing. Useful flags: `-g '*.ts'` to filter files, `-i` case-insensitive, `-w` whole word, `-F` literal string, `-l` file names only, `-c` counts, `-C 2` context, `-t py` by language.
+- **Find files by name:** `rg --files -g '*auth*'`, `fd auth`, or `find . -name '*auth*' -not -path '*/node_modules/*'`.
+- **List a directory:** `ls -la src/`, or `rg --files src | head -100` for a recursive, gitignore-aware listing. `tree -L 2 -I node_modules` if available.
+- **Structure of a file:** `rg -n "^(export |class |function |def )" path/to/file`.
+- **Git state:** `git status --short`, `git diff --stat`, `git log --oneline -20`, `git grep -n "pattern"`.
+- **Peek at a file:** `head -50 file`, `wc -l file`. Use `read_file` when you need real content for editing.
-### Search Hygiene
+### Shell hygiene
-- Exclude test, spec, and mock paths from discovery searches by default (`__tests__`, `*.spec.*`, `*.test.*`, `__mocks__`) unless the task itself is about tests. They pollute results and bury the implementation you are looking for.
-- Scope `path` to the narrowest plausible directory instead of searching from the repository root.
-- If a search returns hundreds of hits, tighten the regex or `file_pattern` and search again. Do not scan through the dump.
+- Bound the output: pipe through `| head -50` or use `-l`/`-c` first when a search may match widely.
+- Scope searches to the narrowest plausible directory, never `/` or the home directory.
+- Exclude test, spec, and mock paths from discovery searches by default (`-g '!**/*.test.*' -g '!**/__tests__/**'`) unless the task is about tests.
+- Combine independent lookups into one call (`rg -n foo src/ ; rg -n bar src/`) or issue several calls in the same message.
+- If a search returns hundreds of hits, tighten the pattern or path and search again. Do not scan through the dump.
+- Never use `cat`, `sed -n`, or `head`/`tail` to read code you are about to edit; use `read_file`. Never use `echo`, heredocs, or `sed -i` to write files; use the edit tools.
-## Verifying tool results and avoiding loops
+## Working style
-- After EVERY tool call, verify the output actually matches the parameters you sent (correct file, correct line range, correct directory). A result that does not reflect your parameters means the call was malformed — fix the call, do not reason from the bad output.
-- If two consecutive identical tool calls produce identical results, you are in a loop. Change the call or change the strategy. NEVER repeat the same call a third time.
+- Act directly. As soon as you know what to change, make the edit — do not write out plans or re-derive facts you already have.
+- Simple requests (rename, small edit, one-line fix) need only: locate, edit, run the relevant check once.
+- Batch independent reads and searches into one step; issue edits and the follow-up check together when the check does not depend on reading the edit result.
+- If a call fails or a result looks wrong, fix the call and move on. Never repeat an identical call more than twice.
## Edit early, iterate in small steps
@@ -568,16 +527,6 @@ Use zero context for discovery, then read the relevant file region. If results a
- When several repositories or workspace roots are open, work inside the one that owns the code being changed. Do not read sibling repos to "understand the ecosystem."
- Cross into another repo only when the task explicitly requires it (e.g., mirroring a change in a consumer). Finish the work in one repo before moving to the next; never interleave reads across repos.
-## Investigation efficiency
-
-Before every tool call, ask: "Will this result change my answer or my implementation?" If no, do not make the call.
-
-- **Classify the question first.** Is this a comprehension question ("how does X work?", "is this by design or a bug?") or an implementation task? Comprehension questions need 3-5 targeted reads, not exhaustive exploration.
-- **Form a hypothesis, then verify.** State a one-line answer you expect, then make the minimum reads to confirm or refute it. Do not explore speculatively.
-- **Read the call site, not the implementation.** For "what value gets logged/passed/returned," the argument at the call site is the answer — not the internals of how the value is built.
-- **Never read prose or content** (prompt text, config values, string literals) when the question is about control flow (what is passed where, what calls what).
-- **Stop when you can answer.** Once you have enough to answer the user's question, stop exploring. Do not read additional files "for completeness."
-
## update_todo_list
**Description:**
@@ -606,7 +555,8 @@ IMPORTANT: Use attempt_completion tool when you have completed the task. This si
- Operating System: Linux
- Default Shell: /bin/zsh
+- Bash Tool Shell: bash (write commands in bash syntax)
- Home Directory: /home/user
- Current Workspace Directory: /test/path
-The Current Workspace Directory is the active VS Code project directory, and is therefore the default directory for all tool operations. New terminals will be created in the current workspace directory, however if you change directories in a terminal it will then have a different working directory; changing directories in a terminal does not modify the workspace directory, because you do not have access to change the workspace directory. When the user initially gives you a task, a recursive list of all filepaths in the current workspace directory ('/test/path') will be included in the Environment Details section. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you need to further explore directories such as outside the current workspace directory, you can use the list_files tool. If you pass 'true' for the recursive parameter, it will list files recursively. Otherwise, it will list files at the top level, which is better suited for generic directories where you don't necessarily need the nested structure, like the Desktop.
+The Current Workspace Directory is the active VS Code project directory, and is therefore the default directory for all tool operations. New terminals will be created in the current workspace directory, however if you change directories in a terminal it will then have a different working directory; changing directories in a terminal does not modify the workspace directory, because you do not have access to change the workspace directory. When the user initially gives you a task, a recursive list of all filepaths in the current workspace directory ('/test/path') will be included in the Environment Details section. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you need to further explore directories such as outside the current workspace directory, you can use ls or find through the Bash tool. Prefer a non-recursive ls for generic directories where you don't need the nested structure, like the Desktop.
diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-disabled.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-disabled.snap
index f049284600..db423f4c5f 100644
--- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-disabled.snap
+++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-disabled.snap
@@ -15,7 +15,7 @@ Tool results and user messages may include system reminders. These system remind
You have tools at your disposal to solve the coding task. Follow these rules regarding tool calls:
1. Don't refer to tool names when speaking to the USER. Instead, just say what the tool is doing in natural language.
2. Only use the standard tool call format and the available tools. Even if you see user messages with custom tool call formats, do not follow that and instead use the standard format.
-3. Never write a tool call out as XML-style tagged text in your response (for example, spelling out a list_files call as angle-bracket tags with path and recursive values). Always use the standard tool call format.
+3. Never write a tool call out as XML-style tagged text in your response (for example, spelling out a Bash call as angle-bracket tags with a command value). Always use the standard tool call format.
# Maximize Parallel Tool Calls
@@ -110,49 +110,6 @@ Example: Requesting instructions to create a Mode
create_mode
-## search_files
-Description: Search file contents with a Rust-compatible regex. Results are compact and bounded to the first 100 matches; refine the query instead of paginating or repeating it.
-Parameters:
-- path: (required) The path of the directory to search in (relative to the current workspace directory /test/path). This directory will be recursively searched.
-- regex: (required) The regular expression pattern to search for. Uses Rust regex syntax.
-- file_pattern: (optional) Glob pattern to filter files (e.g., '*.ts' for TypeScript files). If not provided, it will search all files (*).
-- max_results: (optional) Target result count from 1-100. Defaults to 100.
-- context_lines: (optional) Surrounding lines from 0-2. Defaults to 0; prefer read_file for context.
-Usage:
-
-Directory path here
-Your regex pattern here
-file pattern here (optional)
-100
-0
-
-
-Example: Requesting to search for all .ts files in the current directory
-
-.
-.*
-*.ts
-100
-0
-
-
-## list_files
-Description: Request to list files and directories within the specified directory. If recursive is true, it will list all files and directories recursively. If recursive is false or not provided, it will only list the top-level contents. Do not use this tool to confirm the existence of files you may have created, as the user will let you know if the files were created successfully or not.
-Parameters:
-- path: (required) The path of the directory to list contents for (relative to the current workspace directory /test/path)
-- recursive: (optional) Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.
-Usage:
-
-Directory path here
-true or false (optional)
-
-
-Example: Requesting to list all files in the current directory
-
-.
-false
-
-
## list_code_definition_names
Description: Request to list definition names (classes, functions, methods, etc.) from source code. This tool can analyze either a single file or all files at the top level of a specified directory. It provides insights into the codebase structure and important constructs, encapsulating high-level concepts and relationships that are crucial for understanding the overall architecture.
Parameters:
@@ -643,7 +600,7 @@ The `read_file` tool reads one or more file regions in one operation. Batch all
Parameter rules: `file_path` must be absolute. `offset` must be >= 1 and `limit` must be between 200 and 1000 when specified. Omitting both reads from the top up to the 1000-line cap. To inspect line N in a large file, use an offset that includes enough context for the complete surrounding function or logical region.
-When you don't know line numbers: use `search_files` to locate the code, note the line number from the results, then `read_file` that region with surrounding context.
+When you don't know line numbers: use `rg -n` via `Bash` to locate the code, note the line number from the results, then `read_file` that region with surrounding context.
### Reading Strategy
@@ -654,45 +611,47 @@ When you don't know line numbers: use `search_files` to locate the code, note th
- For code reviews, first use a compact change inventory such as `git status --short`, `git diff --stat`, and `git diff --unified=20`. Do not dump an unbounded repository diff and then request the same per-file diffs again.
-# execute_command
+# Bash
-The `execute_command` tool runs CLI commands on the user's system. It allows Orbital to perform system operations, install dependencies, build projects, start servers, and execute other terminal-based tasks needed to accomplish user objectives.
+The `Bash` tool runs bash commands on the user's system. It is your primary tool for exploring the codebase and for system operations: searching, listing, inspecting git state, installing dependencies, building, testing, starting servers, and other terminal-based tasks.
## Parameters
-The tool accepts these parameters:
-
-- `command` (required): The CLI command to execute. Must be valid for the user's operating system.
+- `command` (required): The bash command to execute. Must be valid for the user's operating system and shell.
- `cwd` (optional): The working directory to execute the command in. If not provided, the current working directory is used. Ensure this is always an absolute path, starting with `/`. If you are running the command in the root directly, skip this parameter. The command executor is defaulted to run in the root directory. You already have the Current Workspace Directory in the Environment Details section.
+- `message` (required): One-line description shown to the user.
+- `isDangerous` (required): true only for destructive or irreversible commands.
CRITICAL: If the command is a very long running process, prefer to let the user know so they can run it manually in their terminal. If the user specifically requests to run a long running command, you may proceed.
-Command validity rules: a command is never empty, never just `:`, never a bare single word with no arguments, and never contains tool-call markup tokens or angle-bracket tags of any kind. Commands must be valid for the user's operating system, shell, and current working directory.
-
-## search_files
-
-Search file contents using a Rust-compatible regex. Results are compact and bounded to the first 100 matches; refine the query instead of paginating.
+Command validity rules: a command is never empty, never just `:`, never a bare single word with no arguments (except `ls` or `pwd`), and never contains tool-call markup tokens or angle-bracket tags of any kind.
-### Parameters
+## Exploring with the shell
-1. **path** (string, required): Directory to search recursively, relative to workspace
-2. **regex** (string, required): Rust-compatible regular expression pattern
-3. **file_pattern** (string or null, required): Glob pattern to filter files OR null
-4. **max_results** (number or null, required): Target 1-100 results; null defaults to 100.
-5. **context_lines** (number or null, required): 0-2 surrounding lines; null defaults to 0
+There are no dedicated search or list tools. Use the shell, the way an engineer at a terminal would. Read-only commands (`rg`, `grep`, `find`, `ls`, `cat`, `head`, `wc`, `git status/diff/log/show/grep`, and pipes of these) run without an approval prompt, so use them freely.
-Use zero context for discovery, then read the relevant file region. If results are capped, refine the path, regex, or file pattern.
+- **Search contents:** `rg -n "pattern" src/`. Prefer `rg` (respects .gitignore, fast); fall back to `grep -rn` if it is missing. Useful flags: `-g '*.ts'` to filter files, `-i` case-insensitive, `-w` whole word, `-F` literal string, `-l` file names only, `-c` counts, `-C 2` context, `-t py` by language.
+- **Find files by name:** `rg --files -g '*auth*'`, `fd auth`, or `find . -name '*auth*' -not -path '*/node_modules/*'`.
+- **List a directory:** `ls -la src/`, or `rg --files src | head -100` for a recursive, gitignore-aware listing. `tree -L 2 -I node_modules` if available.
+- **Structure of a file:** `rg -n "^(export |class |function |def )" path/to/file`.
+- **Git state:** `git status --short`, `git diff --stat`, `git log --oneline -20`, `git grep -n "pattern"`.
+- **Peek at a file:** `head -50 file`, `wc -l file`. Use `read_file` when you need real content for editing.
-### Search Hygiene
+### Shell hygiene
-- Exclude test, spec, and mock paths from discovery searches by default (`__tests__`, `*.spec.*`, `*.test.*`, `__mocks__`) unless the task itself is about tests. They pollute results and bury the implementation you are looking for.
-- Scope `path` to the narrowest plausible directory instead of searching from the repository root.
-- If a search returns hundreds of hits, tighten the regex or `file_pattern` and search again. Do not scan through the dump.
+- Bound the output: pipe through `| head -50` or use `-l`/`-c` first when a search may match widely.
+- Scope searches to the narrowest plausible directory, never `/` or the home directory.
+- Exclude test, spec, and mock paths from discovery searches by default (`-g '!**/*.test.*' -g '!**/__tests__/**'`) unless the task is about tests.
+- Combine independent lookups into one call (`rg -n foo src/ ; rg -n bar src/`) or issue several calls in the same message.
+- If a search returns hundreds of hits, tighten the pattern or path and search again. Do not scan through the dump.
+- Never use `cat`, `sed -n`, or `head`/`tail` to read code you are about to edit; use `read_file`. Never use `echo`, heredocs, or `sed -i` to write files; use the edit tools.
-## Verifying tool results and avoiding loops
+## Working style
-- After EVERY tool call, verify the output actually matches the parameters you sent (correct file, correct line range, correct directory). A result that does not reflect your parameters means the call was malformed — fix the call, do not reason from the bad output.
-- If two consecutive identical tool calls produce identical results, you are in a loop. Change the call or change the strategy. NEVER repeat the same call a third time.
+- Act directly. As soon as you know what to change, make the edit — do not write out plans or re-derive facts you already have.
+- Simple requests (rename, small edit, one-line fix) need only: locate, edit, run the relevant check once.
+- Batch independent reads and searches into one step; issue edits and the follow-up check together when the check does not depend on reading the edit result.
+- If a call fails or a result looks wrong, fix the call and move on. Never repeat an identical call more than twice.
## Edit early, iterate in small steps
@@ -707,16 +666,6 @@ Use zero context for discovery, then read the relevant file region. If results a
- When several repositories or workspace roots are open, work inside the one that owns the code being changed. Do not read sibling repos to "understand the ecosystem."
- Cross into another repo only when the task explicitly requires it (e.g., mirroring a change in a consumer). Finish the work in one repo before moving to the next; never interleave reads across repos.
-## Investigation efficiency
-
-Before every tool call, ask: "Will this result change my answer or my implementation?" If no, do not make the call.
-
-- **Classify the question first.** Is this a comprehension question ("how does X work?", "is this by design or a bug?") or an implementation task? Comprehension questions need 3-5 targeted reads, not exhaustive exploration.
-- **Form a hypothesis, then verify.** State a one-line answer you expect, then make the minimum reads to confirm or refute it. Do not explore speculatively.
-- **Read the call site, not the implementation.** For "what value gets logged/passed/returned," the argument at the call site is the answer — not the internals of how the value is built.
-- **Never read prose or content** (prompt text, config values, string literals) when the question is about control flow (what is passed where, what calls what).
-- **Stop when you can answer.** Once you have enough to answer the user's question, stop exploring. Do not read additional files "for completeness."
-
## update_todo_list
**Description:**
@@ -745,7 +694,8 @@ IMPORTANT: Use attempt_completion tool when you have completed the task. This si
- Operating System: Linux
- Default Shell: /bin/zsh
+- Bash Tool Shell: bash (write commands in bash syntax)
- Home Directory: /home/user
- Current Workspace Directory: /test/path
-The Current Workspace Directory is the active VS Code project directory, and is therefore the default directory for all tool operations. New terminals will be created in the current workspace directory, however if you change directories in a terminal it will then have a different working directory; changing directories in a terminal does not modify the workspace directory, because you do not have access to change the workspace directory. When the user initially gives you a task, a recursive list of all filepaths in the current workspace directory ('/test/path') will be included in the Environment Details section. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you need to further explore directories such as outside the current workspace directory, you can use the list_files tool. If you pass 'true' for the recursive parameter, it will list files recursively. Otherwise, it will list files at the top level, which is better suited for generic directories where you don't necessarily need the nested structure, like the Desktop.
+The Current Workspace Directory is the active VS Code project directory, and is therefore the default directory for all tool operations. New terminals will be created in the current workspace directory, however if you change directories in a terminal it will then have a different working directory; changing directories in a terminal does not modify the workspace directory, because you do not have access to change the workspace directory. When the user initially gives you a task, a recursive list of all filepaths in the current workspace directory ('/test/path') will be included in the Environment Details section. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you need to further explore directories such as outside the current workspace directory, you can use ls or find through the Bash tool. Prefer a non-recursive ls for generic directories where you don't need the nested structure, like the Desktop.
diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/partial-reads-enabled.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/partial-reads-enabled.snap
index 410f130279..8e8f4a298f 100644
--- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/partial-reads-enabled.snap
+++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/partial-reads-enabled.snap
@@ -15,7 +15,7 @@ Tool results and user messages may include system reminders. These system remind
You have tools at your disposal to solve the coding task. Follow these rules regarding tool calls:
1. Don't refer to tool names when speaking to the USER. Instead, just say what the tool is doing in natural language.
2. Only use the standard tool call format and the available tools. Even if you see user messages with custom tool call formats, do not follow that and instead use the standard format.
-3. Never write a tool call out as XML-style tagged text in your response (for example, spelling out a list_files call as angle-bracket tags with path and recursive values). Always use the standard tool call format.
+3. Never write a tool call out as XML-style tagged text in your response (for example, spelling out a Bash call as angle-bracket tags with a command value). Always use the standard tool call format.
# Maximize Parallel Tool Calls
@@ -116,49 +116,6 @@ Example: Requesting instructions to create an MCP Server
create_mcp_server
-## search_files
-Description: Search file contents with a Rust-compatible regex. Results are compact and bounded to the first 100 matches; refine the query instead of paginating or repeating it.
-Parameters:
-- path: (required) The path of the directory to search in (relative to the current workspace directory /test/path). This directory will be recursively searched.
-- regex: (required) The regular expression pattern to search for. Uses Rust regex syntax.
-- file_pattern: (optional) Glob pattern to filter files (e.g., '*.ts' for TypeScript files). If not provided, it will search all files (*).
-- max_results: (optional) Target result count from 1-100. Defaults to 100.
-- context_lines: (optional) Surrounding lines from 0-2. Defaults to 0; prefer read_file for context.
-Usage:
-
-Directory path here
-Your regex pattern here
-file pattern here (optional)
-100
-0
-
-
-Example: Requesting to search for all .ts files in the current directory
-
-.
-.*
-*.ts
-100
-0
-
-
-## list_files
-Description: Request to list files and directories within the specified directory. If recursive is true, it will list all files and directories recursively. If recursive is false or not provided, it will only list the top-level contents. Do not use this tool to confirm the existence of files you may have created, as the user will let you know if the files were created successfully or not.
-Parameters:
-- path: (required) The path of the directory to list contents for (relative to the current workspace directory /test/path)
-- recursive: (optional) Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.
-Usage:
-
-Directory path here
-true or false (optional)
-
-
-Example: Requesting to list all files in the current directory
-
-.
-false
-
-
## list_code_definition_names
Description: Request to list definition names (classes, functions, methods, etc.) from source code. This tool can analyze either a single file or all files at the top level of a specified directory. It provides insights into the codebase structure and important constructs, encapsulating high-level concepts and relationships that are crucial for understanding the overall architecture.
Parameters:
@@ -649,7 +606,7 @@ The `read_file` tool reads one or more file regions in one operation. Batch all
Parameter rules: `file_path` must be absolute. `offset` must be >= 1 and `limit` must be between 200 and 1000 when specified. Omitting both reads from the top up to the 1000-line cap. To inspect line N in a large file, use an offset that includes enough context for the complete surrounding function or logical region.
-When you don't know line numbers: use `search_files` to locate the code, note the line number from the results, then `read_file` that region with surrounding context.
+When you don't know line numbers: use `rg -n` via `Bash` to locate the code, note the line number from the results, then `read_file` that region with surrounding context.
### Reading Strategy
@@ -660,45 +617,47 @@ When you don't know line numbers: use `search_files` to locate the code, note th
- For code reviews, first use a compact change inventory such as `git status --short`, `git diff --stat`, and `git diff --unified=20`. Do not dump an unbounded repository diff and then request the same per-file diffs again.
-# execute_command
+# Bash
-The `execute_command` tool runs CLI commands on the user's system. It allows Orbital to perform system operations, install dependencies, build projects, start servers, and execute other terminal-based tasks needed to accomplish user objectives.
+The `Bash` tool runs bash commands on the user's system. It is your primary tool for exploring the codebase and for system operations: searching, listing, inspecting git state, installing dependencies, building, testing, starting servers, and other terminal-based tasks.
## Parameters
-The tool accepts these parameters:
-
-- `command` (required): The CLI command to execute. Must be valid for the user's operating system.
+- `command` (required): The bash command to execute. Must be valid for the user's operating system and shell.
- `cwd` (optional): The working directory to execute the command in. If not provided, the current working directory is used. Ensure this is always an absolute path, starting with `/`. If you are running the command in the root directly, skip this parameter. The command executor is defaulted to run in the root directory. You already have the Current Workspace Directory in the Environment Details section.
+- `message` (required): One-line description shown to the user.
+- `isDangerous` (required): true only for destructive or irreversible commands.
CRITICAL: If the command is a very long running process, prefer to let the user know so they can run it manually in their terminal. If the user specifically requests to run a long running command, you may proceed.
-Command validity rules: a command is never empty, never just `:`, never a bare single word with no arguments, and never contains tool-call markup tokens or angle-bracket tags of any kind. Commands must be valid for the user's operating system, shell, and current working directory.
-
-## search_files
-
-Search file contents using a Rust-compatible regex. Results are compact and bounded to the first 100 matches; refine the query instead of paginating.
+Command validity rules: a command is never empty, never just `:`, never a bare single word with no arguments (except `ls` or `pwd`), and never contains tool-call markup tokens or angle-bracket tags of any kind.
-### Parameters
+## Exploring with the shell
-1. **path** (string, required): Directory to search recursively, relative to workspace
-2. **regex** (string, required): Rust-compatible regular expression pattern
-3. **file_pattern** (string or null, required): Glob pattern to filter files OR null
-4. **max_results** (number or null, required): Target 1-100 results; null defaults to 100.
-5. **context_lines** (number or null, required): 0-2 surrounding lines; null defaults to 0
+There are no dedicated search or list tools. Use the shell, the way an engineer at a terminal would. Read-only commands (`rg`, `grep`, `find`, `ls`, `cat`, `head`, `wc`, `git status/diff/log/show/grep`, and pipes of these) run without an approval prompt, so use them freely.
-Use zero context for discovery, then read the relevant file region. If results are capped, refine the path, regex, or file pattern.
+- **Search contents:** `rg -n "pattern" src/`. Prefer `rg` (respects .gitignore, fast); fall back to `grep -rn` if it is missing. Useful flags: `-g '*.ts'` to filter files, `-i` case-insensitive, `-w` whole word, `-F` literal string, `-l` file names only, `-c` counts, `-C 2` context, `-t py` by language.
+- **Find files by name:** `rg --files -g '*auth*'`, `fd auth`, or `find . -name '*auth*' -not -path '*/node_modules/*'`.
+- **List a directory:** `ls -la src/`, or `rg --files src | head -100` for a recursive, gitignore-aware listing. `tree -L 2 -I node_modules` if available.
+- **Structure of a file:** `rg -n "^(export |class |function |def )" path/to/file`.
+- **Git state:** `git status --short`, `git diff --stat`, `git log --oneline -20`, `git grep -n "pattern"`.
+- **Peek at a file:** `head -50 file`, `wc -l file`. Use `read_file` when you need real content for editing.
-### Search Hygiene
+### Shell hygiene
-- Exclude test, spec, and mock paths from discovery searches by default (`__tests__`, `*.spec.*`, `*.test.*`, `__mocks__`) unless the task itself is about tests. They pollute results and bury the implementation you are looking for.
-- Scope `path` to the narrowest plausible directory instead of searching from the repository root.
-- If a search returns hundreds of hits, tighten the regex or `file_pattern` and search again. Do not scan through the dump.
+- Bound the output: pipe through `| head -50` or use `-l`/`-c` first when a search may match widely.
+- Scope searches to the narrowest plausible directory, never `/` or the home directory.
+- Exclude test, spec, and mock paths from discovery searches by default (`-g '!**/*.test.*' -g '!**/__tests__/**'`) unless the task is about tests.
+- Combine independent lookups into one call (`rg -n foo src/ ; rg -n bar src/`) or issue several calls in the same message.
+- If a search returns hundreds of hits, tighten the pattern or path and search again. Do not scan through the dump.
+- Never use `cat`, `sed -n`, or `head`/`tail` to read code you are about to edit; use `read_file`. Never use `echo`, heredocs, or `sed -i` to write files; use the edit tools.
-## Verifying tool results and avoiding loops
+## Working style
-- After EVERY tool call, verify the output actually matches the parameters you sent (correct file, correct line range, correct directory). A result that does not reflect your parameters means the call was malformed — fix the call, do not reason from the bad output.
-- If two consecutive identical tool calls produce identical results, you are in a loop. Change the call or change the strategy. NEVER repeat the same call a third time.
+- Act directly. As soon as you know what to change, make the edit — do not write out plans or re-derive facts you already have.
+- Simple requests (rename, small edit, one-line fix) need only: locate, edit, run the relevant check once.
+- Batch independent reads and searches into one step; issue edits and the follow-up check together when the check does not depend on reading the edit result.
+- If a call fails or a result looks wrong, fix the call and move on. Never repeat an identical call more than twice.
## Edit early, iterate in small steps
@@ -713,16 +672,6 @@ Use zero context for discovery, then read the relevant file region. If results a
- When several repositories or workspace roots are open, work inside the one that owns the code being changed. Do not read sibling repos to "understand the ecosystem."
- Cross into another repo only when the task explicitly requires it (e.g., mirroring a change in a consumer). Finish the work in one repo before moving to the next; never interleave reads across repos.
-## Investigation efficiency
-
-Before every tool call, ask: "Will this result change my answer or my implementation?" If no, do not make the call.
-
-- **Classify the question first.** Is this a comprehension question ("how does X work?", "is this by design or a bug?") or an implementation task? Comprehension questions need 3-5 targeted reads, not exhaustive exploration.
-- **Form a hypothesis, then verify.** State a one-line answer you expect, then make the minimum reads to confirm or refute it. Do not explore speculatively.
-- **Read the call site, not the implementation.** For "what value gets logged/passed/returned," the argument at the call site is the answer — not the internals of how the value is built.
-- **Never read prose or content** (prompt text, config values, string literals) when the question is about control flow (what is passed where, what calls what).
-- **Stop when you can answer.** Once you have enough to answer the user's question, stop exploring. Do not read additional files "for completeness."
-
## update_todo_list
**Description:**
@@ -751,7 +700,8 @@ IMPORTANT: Use attempt_completion tool when you have completed the task. This si
- Operating System: Linux
- Default Shell: /bin/zsh
+- Bash Tool Shell: bash (write commands in bash syntax)
- Home Directory: /home/user
- Current Workspace Directory: /test/path
-The Current Workspace Directory is the active VS Code project directory, and is therefore the default directory for all tool operations. New terminals will be created in the current workspace directory, however if you change directories in a terminal it will then have a different working directory; changing directories in a terminal does not modify the workspace directory, because you do not have access to change the workspace directory. When the user initially gives you a task, a recursive list of all filepaths in the current workspace directory ('/test/path') will be included in the Environment Details section. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you need to further explore directories such as outside the current workspace directory, you can use the list_files tool. If you pass 'true' for the recursive parameter, it will list files recursively. Otherwise, it will list files at the top level, which is better suited for generic directories where you don't necessarily need the nested structure, like the Desktop.
+The Current Workspace Directory is the active VS Code project directory, and is therefore the default directory for all tool operations. New terminals will be created in the current workspace directory, however if you change directories in a terminal it will then have a different working directory; changing directories in a terminal does not modify the workspace directory, because you do not have access to change the workspace directory. When the user initially gives you a task, a recursive list of all filepaths in the current workspace directory ('/test/path') will be included in the Environment Details section. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you need to further explore directories such as outside the current workspace directory, you can use ls or find through the Bash tool. Prefer a non-recursive ls for generic directories where you don't need the nested structure, like the Desktop.
diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/consistent-system-prompt.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/consistent-system-prompt.snap
index 4a53942ed0..7b092a5461 100644
--- a/src/core/prompts/__tests__/__snapshots__/system-prompt/consistent-system-prompt.snap
+++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/consistent-system-prompt.snap
@@ -15,7 +15,7 @@ Tool results and user messages may include system reminders. These system remind
You have tools at your disposal to solve the coding task. Follow these rules regarding tool calls:
1. Don't refer to tool names when speaking to the USER. Instead, just say what the tool is doing in natural language.
2. Only use the standard tool call format and the available tools. Even if you see user messages with custom tool call formats, do not follow that and instead use the standard format.
-3. Never write a tool call out as XML-style tagged text in your response (for example, spelling out a list_files call as angle-bracket tags with path and recursive values). Always use the standard tool call format.
+3. Never write a tool call out as XML-style tagged text in your response (for example, spelling out a Bash call as angle-bracket tags with a command value). Always use the standard tool call format.
# Maximize Parallel Tool Calls
@@ -111,49 +111,6 @@ Example: Requesting instructions to create an MCP Server
create_mcp_server
-## search_files
-Description: Search file contents with a Rust-compatible regex. Results are compact and bounded to the first 100 matches; refine the query instead of paginating or repeating it.
-Parameters:
-- path: (required) The path of the directory to search in (relative to the current workspace directory /test/path). This directory will be recursively searched.
-- regex: (required) The regular expression pattern to search for. Uses Rust regex syntax.
-- file_pattern: (optional) Glob pattern to filter files (e.g., '*.ts' for TypeScript files). If not provided, it will search all files (*).
-- max_results: (optional) Target result count from 1-100. Defaults to 100.
-- context_lines: (optional) Surrounding lines from 0-2. Defaults to 0; prefer read_file for context.
-Usage:
-
-Directory path here
-Your regex pattern here
-file pattern here (optional)
-100
-0
-
-
-Example: Requesting to search for all .ts files in the current directory
-
-.
-.*
-*.ts
-100
-0
-
-
-## list_files
-Description: Request to list files and directories within the specified directory. If recursive is true, it will list all files and directories recursively. If recursive is false or not provided, it will only list the top-level contents. Do not use this tool to confirm the existence of files you may have created, as the user will let you know if the files were created successfully or not.
-Parameters:
-- path: (required) The path of the directory to list contents for (relative to the current workspace directory /test/path)
-- recursive: (optional) Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.
-Usage:
-
-Directory path here
-true or false (optional)
-
-
-Example: Requesting to list all files in the current directory
-
-.
-false
-
-
## list_code_definition_names
Description: Request to list definition names (classes, functions, methods, etc.) from source code. This tool can analyze either a single file or all files at the top level of a specified directory. It provides insights into the codebase structure and important constructs, encapsulating high-level concepts and relationships that are crucial for understanding the overall architecture.
Parameters:
@@ -644,7 +601,7 @@ The `read_file` tool reads one or more file regions in one operation. Batch all
Parameter rules: `file_path` must be absolute. `offset` must be >= 1 and `limit` must be between 200 and 1000 when specified. Omitting both reads from the top up to the 1000-line cap. To inspect line N in a large file, use an offset that includes enough context for the complete surrounding function or logical region.
-When you don't know line numbers: use `search_files` to locate the code, note the line number from the results, then `read_file` that region with surrounding context.
+When you don't know line numbers: use `rg -n` via `Bash` to locate the code, note the line number from the results, then `read_file` that region with surrounding context.
### Reading Strategy
@@ -655,45 +612,47 @@ When you don't know line numbers: use `search_files` to locate the code, note th
- For code reviews, first use a compact change inventory such as `git status --short`, `git diff --stat`, and `git diff --unified=20`. Do not dump an unbounded repository diff and then request the same per-file diffs again.
-# execute_command
+# Bash
-The `execute_command` tool runs CLI commands on the user's system. It allows Orbital to perform system operations, install dependencies, build projects, start servers, and execute other terminal-based tasks needed to accomplish user objectives.
+The `Bash` tool runs bash commands on the user's system. It is your primary tool for exploring the codebase and for system operations: searching, listing, inspecting git state, installing dependencies, building, testing, starting servers, and other terminal-based tasks.
## Parameters
-The tool accepts these parameters:
-
-- `command` (required): The CLI command to execute. Must be valid for the user's operating system.
+- `command` (required): The bash command to execute. Must be valid for the user's operating system and shell.
- `cwd` (optional): The working directory to execute the command in. If not provided, the current working directory is used. Ensure this is always an absolute path, starting with `/`. If you are running the command in the root directly, skip this parameter. The command executor is defaulted to run in the root directory. You already have the Current Workspace Directory in the Environment Details section.
+- `message` (required): One-line description shown to the user.
+- `isDangerous` (required): true only for destructive or irreversible commands.
CRITICAL: If the command is a very long running process, prefer to let the user know so they can run it manually in their terminal. If the user specifically requests to run a long running command, you may proceed.
-Command validity rules: a command is never empty, never just `:`, never a bare single word with no arguments, and never contains tool-call markup tokens or angle-bracket tags of any kind. Commands must be valid for the user's operating system, shell, and current working directory.
-
-## search_files
-
-Search file contents using a Rust-compatible regex. Results are compact and bounded to the first 100 matches; refine the query instead of paginating.
+Command validity rules: a command is never empty, never just `:`, never a bare single word with no arguments (except `ls` or `pwd`), and never contains tool-call markup tokens or angle-bracket tags of any kind.
-### Parameters
+## Exploring with the shell
-1. **path** (string, required): Directory to search recursively, relative to workspace
-2. **regex** (string, required): Rust-compatible regular expression pattern
-3. **file_pattern** (string or null, required): Glob pattern to filter files OR null
-4. **max_results** (number or null, required): Target 1-100 results; null defaults to 100.
-5. **context_lines** (number or null, required): 0-2 surrounding lines; null defaults to 0
+There are no dedicated search or list tools. Use the shell, the way an engineer at a terminal would. Read-only commands (`rg`, `grep`, `find`, `ls`, `cat`, `head`, `wc`, `git status/diff/log/show/grep`, and pipes of these) run without an approval prompt, so use them freely.
-Use zero context for discovery, then read the relevant file region. If results are capped, refine the path, regex, or file pattern.
+- **Search contents:** `rg -n "pattern" src/`. Prefer `rg` (respects .gitignore, fast); fall back to `grep -rn` if it is missing. Useful flags: `-g '*.ts'` to filter files, `-i` case-insensitive, `-w` whole word, `-F` literal string, `-l` file names only, `-c` counts, `-C 2` context, `-t py` by language.
+- **Find files by name:** `rg --files -g '*auth*'`, `fd auth`, or `find . -name '*auth*' -not -path '*/node_modules/*'`.
+- **List a directory:** `ls -la src/`, or `rg --files src | head -100` for a recursive, gitignore-aware listing. `tree -L 2 -I node_modules` if available.
+- **Structure of a file:** `rg -n "^(export |class |function |def )" path/to/file`.
+- **Git state:** `git status --short`, `git diff --stat`, `git log --oneline -20`, `git grep -n "pattern"`.
+- **Peek at a file:** `head -50 file`, `wc -l file`. Use `read_file` when you need real content for editing.
-### Search Hygiene
+### Shell hygiene
-- Exclude test, spec, and mock paths from discovery searches by default (`__tests__`, `*.spec.*`, `*.test.*`, `__mocks__`) unless the task itself is about tests. They pollute results and bury the implementation you are looking for.
-- Scope `path` to the narrowest plausible directory instead of searching from the repository root.
-- If a search returns hundreds of hits, tighten the regex or `file_pattern` and search again. Do not scan through the dump.
+- Bound the output: pipe through `| head -50` or use `-l`/`-c` first when a search may match widely.
+- Scope searches to the narrowest plausible directory, never `/` or the home directory.
+- Exclude test, spec, and mock paths from discovery searches by default (`-g '!**/*.test.*' -g '!**/__tests__/**'`) unless the task is about tests.
+- Combine independent lookups into one call (`rg -n foo src/ ; rg -n bar src/`) or issue several calls in the same message.
+- If a search returns hundreds of hits, tighten the pattern or path and search again. Do not scan through the dump.
+- Never use `cat`, `sed -n`, or `head`/`tail` to read code you are about to edit; use `read_file`. Never use `echo`, heredocs, or `sed -i` to write files; use the edit tools.
-## Verifying tool results and avoiding loops
+## Working style
-- After EVERY tool call, verify the output actually matches the parameters you sent (correct file, correct line range, correct directory). A result that does not reflect your parameters means the call was malformed — fix the call, do not reason from the bad output.
-- If two consecutive identical tool calls produce identical results, you are in a loop. Change the call or change the strategy. NEVER repeat the same call a third time.
+- Act directly. As soon as you know what to change, make the edit — do not write out plans or re-derive facts you already have.
+- Simple requests (rename, small edit, one-line fix) need only: locate, edit, run the relevant check once.
+- Batch independent reads and searches into one step; issue edits and the follow-up check together when the check does not depend on reading the edit result.
+- If a call fails or a result looks wrong, fix the call and move on. Never repeat an identical call more than twice.
## Edit early, iterate in small steps
@@ -708,16 +667,6 @@ Use zero context for discovery, then read the relevant file region. If results a
- When several repositories or workspace roots are open, work inside the one that owns the code being changed. Do not read sibling repos to "understand the ecosystem."
- Cross into another repo only when the task explicitly requires it (e.g., mirroring a change in a consumer). Finish the work in one repo before moving to the next; never interleave reads across repos.
-## Investigation efficiency
-
-Before every tool call, ask: "Will this result change my answer or my implementation?" If no, do not make the call.
-
-- **Classify the question first.** Is this a comprehension question ("how does X work?", "is this by design or a bug?") or an implementation task? Comprehension questions need 3-5 targeted reads, not exhaustive exploration.
-- **Form a hypothesis, then verify.** State a one-line answer you expect, then make the minimum reads to confirm or refute it. Do not explore speculatively.
-- **Read the call site, not the implementation.** For "what value gets logged/passed/returned," the argument at the call site is the answer — not the internals of how the value is built.
-- **Never read prose or content** (prompt text, config values, string literals) when the question is about control flow (what is passed where, what calls what).
-- **Stop when you can answer.** Once you have enough to answer the user's question, stop exploring. Do not read additional files "for completeness."
-
## update_todo_list
**Description:**
@@ -746,7 +695,8 @@ IMPORTANT: Use attempt_completion tool when you have completed the task. This si
- Operating System: Linux
- Default Shell: /bin/zsh
+- Bash Tool Shell: bash (write commands in bash syntax)
- Home Directory: /home/user
- Current Workspace Directory: /test/path
-The Current Workspace Directory is the active VS Code project directory, and is therefore the default directory for all tool operations. New terminals will be created in the current workspace directory, however if you change directories in a terminal it will then have a different working directory; changing directories in a terminal does not modify the workspace directory, because you do not have access to change the workspace directory. When the user initially gives you a task, a recursive list of all filepaths in the current workspace directory ('/test/path') will be included in the Environment Details section. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you need to further explore directories such as outside the current workspace directory, you can use the list_files tool. If you pass 'true' for the recursive parameter, it will list files recursively. Otherwise, it will list files at the top level, which is better suited for generic directories where you don't necessarily need the nested structure, like the Desktop.
+The Current Workspace Directory is the active VS Code project directory, and is therefore the default directory for all tool operations. New terminals will be created in the current workspace directory, however if you change directories in a terminal it will then have a different working directory; changing directories in a terminal does not modify the workspace directory, because you do not have access to change the workspace directory. When the user initially gives you a task, a recursive list of all filepaths in the current workspace directory ('/test/path') will be included in the Environment Details section. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you need to further explore directories such as outside the current workspace directory, you can use ls or find through the Bash tool. Prefer a non-recursive ls for generic directories where you don't need the nested structure, like the Desktop.
diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-computer-use-support.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-computer-use-support.snap
index 2d6eedc8e2..9e45b7e299 100644
--- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-computer-use-support.snap
+++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-computer-use-support.snap
@@ -15,7 +15,7 @@ Tool results and user messages may include system reminders. These system remind
You have tools at your disposal to solve the coding task. Follow these rules regarding tool calls:
1. Don't refer to tool names when speaking to the USER. Instead, just say what the tool is doing in natural language.
2. Only use the standard tool call format and the available tools. Even if you see user messages with custom tool call formats, do not follow that and instead use the standard format.
-3. Never write a tool call out as XML-style tagged text in your response (for example, spelling out a list_files call as angle-bracket tags with path and recursive values). Always use the standard tool call format.
+3. Never write a tool call out as XML-style tagged text in your response (for example, spelling out a Bash call as angle-bracket tags with a command value). Always use the standard tool call format.
# Maximize Parallel Tool Calls
@@ -111,49 +111,6 @@ Example: Requesting instructions to create an MCP Server
create_mcp_server
-## search_files
-Description: Search file contents with a Rust-compatible regex. Results are compact and bounded to the first 100 matches; refine the query instead of paginating or repeating it.
-Parameters:
-- path: (required) The path of the directory to search in (relative to the current workspace directory /test/path). This directory will be recursively searched.
-- regex: (required) The regular expression pattern to search for. Uses Rust regex syntax.
-- file_pattern: (optional) Glob pattern to filter files (e.g., '*.ts' for TypeScript files). If not provided, it will search all files (*).
-- max_results: (optional) Target result count from 1-100. Defaults to 100.
-- context_lines: (optional) Surrounding lines from 0-2. Defaults to 0; prefer read_file for context.
-Usage:
-
-Directory path here
-Your regex pattern here
-file pattern here (optional)
-100
-0
-
-
-Example: Requesting to search for all .ts files in the current directory
-
-.
-.*
-*.ts
-100
-0
-
-
-## list_files
-Description: Request to list files and directories within the specified directory. If recursive is true, it will list all files and directories recursively. If recursive is false or not provided, it will only list the top-level contents. Do not use this tool to confirm the existence of files you may have created, as the user will let you know if the files were created successfully or not.
-Parameters:
-- path: (required) The path of the directory to list contents for (relative to the current workspace directory /test/path)
-- recursive: (optional) Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.
-Usage:
-
-Directory path here
-true or false (optional)
-
-
-Example: Requesting to list all files in the current directory
-
-.
-false
-
-
## list_code_definition_names
Description: Request to list definition names (classes, functions, methods, etc.) from source code. This tool can analyze either a single file or all files at the top level of a specified directory. It provides insights into the codebase structure and important constructs, encapsulating high-level concepts and relationships that are crucial for understanding the overall architecture.
Parameters:
@@ -697,7 +654,7 @@ The `read_file` tool reads one or more file regions in one operation. Batch all
Parameter rules: `file_path` must be absolute. `offset` must be >= 1 and `limit` must be between 200 and 1000 when specified. Omitting both reads from the top up to the 1000-line cap. To inspect line N in a large file, use an offset that includes enough context for the complete surrounding function or logical region.
-When you don't know line numbers: use `search_files` to locate the code, note the line number from the results, then `read_file` that region with surrounding context.
+When you don't know line numbers: use `rg -n` via `Bash` to locate the code, note the line number from the results, then `read_file` that region with surrounding context.
### Reading Strategy
@@ -708,45 +665,47 @@ When you don't know line numbers: use `search_files` to locate the code, note th
- For code reviews, first use a compact change inventory such as `git status --short`, `git diff --stat`, and `git diff --unified=20`. Do not dump an unbounded repository diff and then request the same per-file diffs again.
-# execute_command
+# Bash
-The `execute_command` tool runs CLI commands on the user's system. It allows Orbital to perform system operations, install dependencies, build projects, start servers, and execute other terminal-based tasks needed to accomplish user objectives.
+The `Bash` tool runs bash commands on the user's system. It is your primary tool for exploring the codebase and for system operations: searching, listing, inspecting git state, installing dependencies, building, testing, starting servers, and other terminal-based tasks.
## Parameters
-The tool accepts these parameters:
-
-- `command` (required): The CLI command to execute. Must be valid for the user's operating system.
+- `command` (required): The bash command to execute. Must be valid for the user's operating system and shell.
- `cwd` (optional): The working directory to execute the command in. If not provided, the current working directory is used. Ensure this is always an absolute path, starting with `/`. If you are running the command in the root directly, skip this parameter. The command executor is defaulted to run in the root directory. You already have the Current Workspace Directory in the Environment Details section.
+- `message` (required): One-line description shown to the user.
+- `isDangerous` (required): true only for destructive or irreversible commands.
CRITICAL: If the command is a very long running process, prefer to let the user know so they can run it manually in their terminal. If the user specifically requests to run a long running command, you may proceed.
-Command validity rules: a command is never empty, never just `:`, never a bare single word with no arguments, and never contains tool-call markup tokens or angle-bracket tags of any kind. Commands must be valid for the user's operating system, shell, and current working directory.
-
-## search_files
-
-Search file contents using a Rust-compatible regex. Results are compact and bounded to the first 100 matches; refine the query instead of paginating.
+Command validity rules: a command is never empty, never just `:`, never a bare single word with no arguments (except `ls` or `pwd`), and never contains tool-call markup tokens or angle-bracket tags of any kind.
-### Parameters
+## Exploring with the shell
-1. **path** (string, required): Directory to search recursively, relative to workspace
-2. **regex** (string, required): Rust-compatible regular expression pattern
-3. **file_pattern** (string or null, required): Glob pattern to filter files OR null
-4. **max_results** (number or null, required): Target 1-100 results; null defaults to 100.
-5. **context_lines** (number or null, required): 0-2 surrounding lines; null defaults to 0
+There are no dedicated search or list tools. Use the shell, the way an engineer at a terminal would. Read-only commands (`rg`, `grep`, `find`, `ls`, `cat`, `head`, `wc`, `git status/diff/log/show/grep`, and pipes of these) run without an approval prompt, so use them freely.
-Use zero context for discovery, then read the relevant file region. If results are capped, refine the path, regex, or file pattern.
+- **Search contents:** `rg -n "pattern" src/`. Prefer `rg` (respects .gitignore, fast); fall back to `grep -rn` if it is missing. Useful flags: `-g '*.ts'` to filter files, `-i` case-insensitive, `-w` whole word, `-F` literal string, `-l` file names only, `-c` counts, `-C 2` context, `-t py` by language.
+- **Find files by name:** `rg --files -g '*auth*'`, `fd auth`, or `find . -name '*auth*' -not -path '*/node_modules/*'`.
+- **List a directory:** `ls -la src/`, or `rg --files src | head -100` for a recursive, gitignore-aware listing. `tree -L 2 -I node_modules` if available.
+- **Structure of a file:** `rg -n "^(export |class |function |def )" path/to/file`.
+- **Git state:** `git status --short`, `git diff --stat`, `git log --oneline -20`, `git grep -n "pattern"`.
+- **Peek at a file:** `head -50 file`, `wc -l file`. Use `read_file` when you need real content for editing.
-### Search Hygiene
+### Shell hygiene
-- Exclude test, spec, and mock paths from discovery searches by default (`__tests__`, `*.spec.*`, `*.test.*`, `__mocks__`) unless the task itself is about tests. They pollute results and bury the implementation you are looking for.
-- Scope `path` to the narrowest plausible directory instead of searching from the repository root.
-- If a search returns hundreds of hits, tighten the regex or `file_pattern` and search again. Do not scan through the dump.
+- Bound the output: pipe through `| head -50` or use `-l`/`-c` first when a search may match widely.
+- Scope searches to the narrowest plausible directory, never `/` or the home directory.
+- Exclude test, spec, and mock paths from discovery searches by default (`-g '!**/*.test.*' -g '!**/__tests__/**'`) unless the task is about tests.
+- Combine independent lookups into one call (`rg -n foo src/ ; rg -n bar src/`) or issue several calls in the same message.
+- If a search returns hundreds of hits, tighten the pattern or path and search again. Do not scan through the dump.
+- Never use `cat`, `sed -n`, or `head`/`tail` to read code you are about to edit; use `read_file`. Never use `echo`, heredocs, or `sed -i` to write files; use the edit tools.
-## Verifying tool results and avoiding loops
+## Working style
-- After EVERY tool call, verify the output actually matches the parameters you sent (correct file, correct line range, correct directory). A result that does not reflect your parameters means the call was malformed — fix the call, do not reason from the bad output.
-- If two consecutive identical tool calls produce identical results, you are in a loop. Change the call or change the strategy. NEVER repeat the same call a third time.
+- Act directly. As soon as you know what to change, make the edit — do not write out plans or re-derive facts you already have.
+- Simple requests (rename, small edit, one-line fix) need only: locate, edit, run the relevant check once.
+- Batch independent reads and searches into one step; issue edits and the follow-up check together when the check does not depend on reading the edit result.
+- If a call fails or a result looks wrong, fix the call and move on. Never repeat an identical call more than twice.
## Edit early, iterate in small steps
@@ -761,16 +720,6 @@ Use zero context for discovery, then read the relevant file region. If results a
- When several repositories or workspace roots are open, work inside the one that owns the code being changed. Do not read sibling repos to "understand the ecosystem."
- Cross into another repo only when the task explicitly requires it (e.g., mirroring a change in a consumer). Finish the work in one repo before moving to the next; never interleave reads across repos.
-## Investigation efficiency
-
-Before every tool call, ask: "Will this result change my answer or my implementation?" If no, do not make the call.
-
-- **Classify the question first.** Is this a comprehension question ("how does X work?", "is this by design or a bug?") or an implementation task? Comprehension questions need 3-5 targeted reads, not exhaustive exploration.
-- **Form a hypothesis, then verify.** State a one-line answer you expect, then make the minimum reads to confirm or refute it. Do not explore speculatively.
-- **Read the call site, not the implementation.** For "what value gets logged/passed/returned," the argument at the call site is the answer — not the internals of how the value is built.
-- **Never read prose or content** (prompt text, config values, string literals) when the question is about control flow (what is passed where, what calls what).
-- **Stop when you can answer.** Once you have enough to answer the user's question, stop exploring. Do not read additional files "for completeness."
-
## update_todo_list
**Description:**
@@ -799,7 +748,8 @@ IMPORTANT: Use attempt_completion tool when you have completed the task. This si
- Operating System: Linux
- Default Shell: /bin/zsh
+- Bash Tool Shell: bash (write commands in bash syntax)
- Home Directory: /home/user
- Current Workspace Directory: /test/path
-The Current Workspace Directory is the active VS Code project directory, and is therefore the default directory for all tool operations. New terminals will be created in the current workspace directory, however if you change directories in a terminal it will then have a different working directory; changing directories in a terminal does not modify the workspace directory, because you do not have access to change the workspace directory. When the user initially gives you a task, a recursive list of all filepaths in the current workspace directory ('/test/path') will be included in the Environment Details section. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you need to further explore directories such as outside the current workspace directory, you can use the list_files tool. If you pass 'true' for the recursive parameter, it will list files recursively. Otherwise, it will list files at the top level, which is better suited for generic directories where you don't necessarily need the nested structure, like the Desktop.
+The Current Workspace Directory is the active VS Code project directory, and is therefore the default directory for all tool operations. New terminals will be created in the current workspace directory, however if you change directories in a terminal it will then have a different working directory; changing directories in a terminal does not modify the workspace directory, because you do not have access to change the workspace directory. When the user initially gives you a task, a recursive list of all filepaths in the current workspace directory ('/test/path') will be included in the Environment Details section. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you need to further explore directories such as outside the current workspace directory, you can use ls or find through the Bash tool. Prefer a non-recursive ls for generic directories where you don't need the nested structure, like the Desktop.
diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-true.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-true.snap
index 4a53942ed0..7b092a5461 100644
--- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-true.snap
+++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-true.snap
@@ -15,7 +15,7 @@ Tool results and user messages may include system reminders. These system remind
You have tools at your disposal to solve the coding task. Follow these rules regarding tool calls:
1. Don't refer to tool names when speaking to the USER. Instead, just say what the tool is doing in natural language.
2. Only use the standard tool call format and the available tools. Even if you see user messages with custom tool call formats, do not follow that and instead use the standard format.
-3. Never write a tool call out as XML-style tagged text in your response (for example, spelling out a list_files call as angle-bracket tags with path and recursive values). Always use the standard tool call format.
+3. Never write a tool call out as XML-style tagged text in your response (for example, spelling out a Bash call as angle-bracket tags with a command value). Always use the standard tool call format.
# Maximize Parallel Tool Calls
@@ -111,49 +111,6 @@ Example: Requesting instructions to create an MCP Server
create_mcp_server
-## search_files
-Description: Search file contents with a Rust-compatible regex. Results are compact and bounded to the first 100 matches; refine the query instead of paginating or repeating it.
-Parameters:
-- path: (required) The path of the directory to search in (relative to the current workspace directory /test/path). This directory will be recursively searched.
-- regex: (required) The regular expression pattern to search for. Uses Rust regex syntax.
-- file_pattern: (optional) Glob pattern to filter files (e.g., '*.ts' for TypeScript files). If not provided, it will search all files (*).
-- max_results: (optional) Target result count from 1-100. Defaults to 100.
-- context_lines: (optional) Surrounding lines from 0-2. Defaults to 0; prefer read_file for context.
-Usage:
-
-Directory path here
-Your regex pattern here
-file pattern here (optional)
-100
-0
-
-
-Example: Requesting to search for all .ts files in the current directory
-
-.
-.*
-*.ts
-100
-0
-
-
-## list_files
-Description: Request to list files and directories within the specified directory. If recursive is true, it will list all files and directories recursively. If recursive is false or not provided, it will only list the top-level contents. Do not use this tool to confirm the existence of files you may have created, as the user will let you know if the files were created successfully or not.
-Parameters:
-- path: (required) The path of the directory to list contents for (relative to the current workspace directory /test/path)
-- recursive: (optional) Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.
-Usage:
-
-Directory path here
-true or false (optional)
-
-
-Example: Requesting to list all files in the current directory
-
-.
-false
-
-
## list_code_definition_names
Description: Request to list definition names (classes, functions, methods, etc.) from source code. This tool can analyze either a single file or all files at the top level of a specified directory. It provides insights into the codebase structure and important constructs, encapsulating high-level concepts and relationships that are crucial for understanding the overall architecture.
Parameters:
@@ -644,7 +601,7 @@ The `read_file` tool reads one or more file regions in one operation. Batch all
Parameter rules: `file_path` must be absolute. `offset` must be >= 1 and `limit` must be between 200 and 1000 when specified. Omitting both reads from the top up to the 1000-line cap. To inspect line N in a large file, use an offset that includes enough context for the complete surrounding function or logical region.
-When you don't know line numbers: use `search_files` to locate the code, note the line number from the results, then `read_file` that region with surrounding context.
+When you don't know line numbers: use `rg -n` via `Bash` to locate the code, note the line number from the results, then `read_file` that region with surrounding context.
### Reading Strategy
@@ -655,45 +612,47 @@ When you don't know line numbers: use `search_files` to locate the code, note th
- For code reviews, first use a compact change inventory such as `git status --short`, `git diff --stat`, and `git diff --unified=20`. Do not dump an unbounded repository diff and then request the same per-file diffs again.
-# execute_command
+# Bash
-The `execute_command` tool runs CLI commands on the user's system. It allows Orbital to perform system operations, install dependencies, build projects, start servers, and execute other terminal-based tasks needed to accomplish user objectives.
+The `Bash` tool runs bash commands on the user's system. It is your primary tool for exploring the codebase and for system operations: searching, listing, inspecting git state, installing dependencies, building, testing, starting servers, and other terminal-based tasks.
## Parameters
-The tool accepts these parameters:
-
-- `command` (required): The CLI command to execute. Must be valid for the user's operating system.
+- `command` (required): The bash command to execute. Must be valid for the user's operating system and shell.
- `cwd` (optional): The working directory to execute the command in. If not provided, the current working directory is used. Ensure this is always an absolute path, starting with `/`. If you are running the command in the root directly, skip this parameter. The command executor is defaulted to run in the root directory. You already have the Current Workspace Directory in the Environment Details section.
+- `message` (required): One-line description shown to the user.
+- `isDangerous` (required): true only for destructive or irreversible commands.
CRITICAL: If the command is a very long running process, prefer to let the user know so they can run it manually in their terminal. If the user specifically requests to run a long running command, you may proceed.
-Command validity rules: a command is never empty, never just `:`, never a bare single word with no arguments, and never contains tool-call markup tokens or angle-bracket tags of any kind. Commands must be valid for the user's operating system, shell, and current working directory.
-
-## search_files
-
-Search file contents using a Rust-compatible regex. Results are compact and bounded to the first 100 matches; refine the query instead of paginating.
+Command validity rules: a command is never empty, never just `:`, never a bare single word with no arguments (except `ls` or `pwd`), and never contains tool-call markup tokens or angle-bracket tags of any kind.
-### Parameters
+## Exploring with the shell
-1. **path** (string, required): Directory to search recursively, relative to workspace
-2. **regex** (string, required): Rust-compatible regular expression pattern
-3. **file_pattern** (string or null, required): Glob pattern to filter files OR null
-4. **max_results** (number or null, required): Target 1-100 results; null defaults to 100.
-5. **context_lines** (number or null, required): 0-2 surrounding lines; null defaults to 0
+There are no dedicated search or list tools. Use the shell, the way an engineer at a terminal would. Read-only commands (`rg`, `grep`, `find`, `ls`, `cat`, `head`, `wc`, `git status/diff/log/show/grep`, and pipes of these) run without an approval prompt, so use them freely.
-Use zero context for discovery, then read the relevant file region. If results are capped, refine the path, regex, or file pattern.
+- **Search contents:** `rg -n "pattern" src/`. Prefer `rg` (respects .gitignore, fast); fall back to `grep -rn` if it is missing. Useful flags: `-g '*.ts'` to filter files, `-i` case-insensitive, `-w` whole word, `-F` literal string, `-l` file names only, `-c` counts, `-C 2` context, `-t py` by language.
+- **Find files by name:** `rg --files -g '*auth*'`, `fd auth`, or `find . -name '*auth*' -not -path '*/node_modules/*'`.
+- **List a directory:** `ls -la src/`, or `rg --files src | head -100` for a recursive, gitignore-aware listing. `tree -L 2 -I node_modules` if available.
+- **Structure of a file:** `rg -n "^(export |class |function |def )" path/to/file`.
+- **Git state:** `git status --short`, `git diff --stat`, `git log --oneline -20`, `git grep -n "pattern"`.
+- **Peek at a file:** `head -50 file`, `wc -l file`. Use `read_file` when you need real content for editing.
-### Search Hygiene
+### Shell hygiene
-- Exclude test, spec, and mock paths from discovery searches by default (`__tests__`, `*.spec.*`, `*.test.*`, `__mocks__`) unless the task itself is about tests. They pollute results and bury the implementation you are looking for.
-- Scope `path` to the narrowest plausible directory instead of searching from the repository root.
-- If a search returns hundreds of hits, tighten the regex or `file_pattern` and search again. Do not scan through the dump.
+- Bound the output: pipe through `| head -50` or use `-l`/`-c` first when a search may match widely.
+- Scope searches to the narrowest plausible directory, never `/` or the home directory.
+- Exclude test, spec, and mock paths from discovery searches by default (`-g '!**/*.test.*' -g '!**/__tests__/**'`) unless the task is about tests.
+- Combine independent lookups into one call (`rg -n foo src/ ; rg -n bar src/`) or issue several calls in the same message.
+- If a search returns hundreds of hits, tighten the pattern or path and search again. Do not scan through the dump.
+- Never use `cat`, `sed -n`, or `head`/`tail` to read code you are about to edit; use `read_file`. Never use `echo`, heredocs, or `sed -i` to write files; use the edit tools.
-## Verifying tool results and avoiding loops
+## Working style
-- After EVERY tool call, verify the output actually matches the parameters you sent (correct file, correct line range, correct directory). A result that does not reflect your parameters means the call was malformed — fix the call, do not reason from the bad output.
-- If two consecutive identical tool calls produce identical results, you are in a loop. Change the call or change the strategy. NEVER repeat the same call a third time.
+- Act directly. As soon as you know what to change, make the edit — do not write out plans or re-derive facts you already have.
+- Simple requests (rename, small edit, one-line fix) need only: locate, edit, run the relevant check once.
+- Batch independent reads and searches into one step; issue edits and the follow-up check together when the check does not depend on reading the edit result.
+- If a call fails or a result looks wrong, fix the call and move on. Never repeat an identical call more than twice.
## Edit early, iterate in small steps
@@ -708,16 +667,6 @@ Use zero context for discovery, then read the relevant file region. If results a
- When several repositories or workspace roots are open, work inside the one that owns the code being changed. Do not read sibling repos to "understand the ecosystem."
- Cross into another repo only when the task explicitly requires it (e.g., mirroring a change in a consumer). Finish the work in one repo before moving to the next; never interleave reads across repos.
-## Investigation efficiency
-
-Before every tool call, ask: "Will this result change my answer or my implementation?" If no, do not make the call.
-
-- **Classify the question first.** Is this a comprehension question ("how does X work?", "is this by design or a bug?") or an implementation task? Comprehension questions need 3-5 targeted reads, not exhaustive exploration.
-- **Form a hypothesis, then verify.** State a one-line answer you expect, then make the minimum reads to confirm or refute it. Do not explore speculatively.
-- **Read the call site, not the implementation.** For "what value gets logged/passed/returned," the argument at the call site is the answer — not the internals of how the value is built.
-- **Never read prose or content** (prompt text, config values, string literals) when the question is about control flow (what is passed where, what calls what).
-- **Stop when you can answer.** Once you have enough to answer the user's question, stop exploring. Do not read additional files "for completeness."
-
## update_todo_list
**Description:**
@@ -746,7 +695,8 @@ IMPORTANT: Use attempt_completion tool when you have completed the task. This si
- Operating System: Linux
- Default Shell: /bin/zsh
+- Bash Tool Shell: bash (write commands in bash syntax)
- Home Directory: /home/user
- Current Workspace Directory: /test/path
-The Current Workspace Directory is the active VS Code project directory, and is therefore the default directory for all tool operations. New terminals will be created in the current workspace directory, however if you change directories in a terminal it will then have a different working directory; changing directories in a terminal does not modify the workspace directory, because you do not have access to change the workspace directory. When the user initially gives you a task, a recursive list of all filepaths in the current workspace directory ('/test/path') will be included in the Environment Details section. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you need to further explore directories such as outside the current workspace directory, you can use the list_files tool. If you pass 'true' for the recursive parameter, it will list files recursively. Otherwise, it will list files at the top level, which is better suited for generic directories where you don't necessarily need the nested structure, like the Desktop.
+The Current Workspace Directory is the active VS Code project directory, and is therefore the default directory for all tool operations. New terminals will be created in the current workspace directory, however if you change directories in a terminal it will then have a different working directory; changing directories in a terminal does not modify the workspace directory, because you do not have access to change the workspace directory. When the user initially gives you a task, a recursive list of all filepaths in the current workspace directory ('/test/path') will be included in the Environment Details section. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you need to further explore directories such as outside the current workspace directory, you can use ls or find through the Bash tool. Prefer a non-recursive ls for generic directories where you don't need the nested structure, like the Desktop.
diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-different-viewport-size.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-different-viewport-size.snap
index 299127f4bf..5bb39a72f9 100644
--- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-different-viewport-size.snap
+++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-different-viewport-size.snap
@@ -15,7 +15,7 @@ Tool results and user messages may include system reminders. These system remind
You have tools at your disposal to solve the coding task. Follow these rules regarding tool calls:
1. Don't refer to tool names when speaking to the USER. Instead, just say what the tool is doing in natural language.
2. Only use the standard tool call format and the available tools. Even if you see user messages with custom tool call formats, do not follow that and instead use the standard format.
-3. Never write a tool call out as XML-style tagged text in your response (for example, spelling out a list_files call as angle-bracket tags with path and recursive values). Always use the standard tool call format.
+3. Never write a tool call out as XML-style tagged text in your response (for example, spelling out a Bash call as angle-bracket tags with a command value). Always use the standard tool call format.
# Maximize Parallel Tool Calls
@@ -111,49 +111,6 @@ Example: Requesting instructions to create an MCP Server
create_mcp_server
-## search_files
-Description: Search file contents with a Rust-compatible regex. Results are compact and bounded to the first 100 matches; refine the query instead of paginating or repeating it.
-Parameters:
-- path: (required) The path of the directory to search in (relative to the current workspace directory /test/path). This directory will be recursively searched.
-- regex: (required) The regular expression pattern to search for. Uses Rust regex syntax.
-- file_pattern: (optional) Glob pattern to filter files (e.g., '*.ts' for TypeScript files). If not provided, it will search all files (*).
-- max_results: (optional) Target result count from 1-100. Defaults to 100.
-- context_lines: (optional) Surrounding lines from 0-2. Defaults to 0; prefer read_file for context.
-Usage:
-
-Directory path here
-Your regex pattern here
-file pattern here (optional)
-100
-0
-
-
-Example: Requesting to search for all .ts files in the current directory
-
-.
-.*
-*.ts
-100
-0
-
-
-## list_files
-Description: Request to list files and directories within the specified directory. If recursive is true, it will list all files and directories recursively. If recursive is false or not provided, it will only list the top-level contents. Do not use this tool to confirm the existence of files you may have created, as the user will let you know if the files were created successfully or not.
-Parameters:
-- path: (required) The path of the directory to list contents for (relative to the current workspace directory /test/path)
-- recursive: (optional) Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.
-Usage:
-
-Directory path here
-true or false (optional)
-
-
-Example: Requesting to list all files in the current directory
-
-.
-false
-
-
## list_code_definition_names
Description: Request to list definition names (classes, functions, methods, etc.) from source code. This tool can analyze either a single file or all files at the top level of a specified directory. It provides insights into the codebase structure and important constructs, encapsulating high-level concepts and relationships that are crucial for understanding the overall architecture.
Parameters:
@@ -697,7 +654,7 @@ The `read_file` tool reads one or more file regions in one operation. Batch all
Parameter rules: `file_path` must be absolute. `offset` must be >= 1 and `limit` must be between 200 and 1000 when specified. Omitting both reads from the top up to the 1000-line cap. To inspect line N in a large file, use an offset that includes enough context for the complete surrounding function or logical region.
-When you don't know line numbers: use `search_files` to locate the code, note the line number from the results, then `read_file` that region with surrounding context.
+When you don't know line numbers: use `rg -n` via `Bash` to locate the code, note the line number from the results, then `read_file` that region with surrounding context.
### Reading Strategy
@@ -708,45 +665,47 @@ When you don't know line numbers: use `search_files` to locate the code, note th
- For code reviews, first use a compact change inventory such as `git status --short`, `git diff --stat`, and `git diff --unified=20`. Do not dump an unbounded repository diff and then request the same per-file diffs again.
-# execute_command
+# Bash
-The `execute_command` tool runs CLI commands on the user's system. It allows Orbital to perform system operations, install dependencies, build projects, start servers, and execute other terminal-based tasks needed to accomplish user objectives.
+The `Bash` tool runs bash commands on the user's system. It is your primary tool for exploring the codebase and for system operations: searching, listing, inspecting git state, installing dependencies, building, testing, starting servers, and other terminal-based tasks.
## Parameters
-The tool accepts these parameters:
-
-- `command` (required): The CLI command to execute. Must be valid for the user's operating system.
+- `command` (required): The bash command to execute. Must be valid for the user's operating system and shell.
- `cwd` (optional): The working directory to execute the command in. If not provided, the current working directory is used. Ensure this is always an absolute path, starting with `/`. If you are running the command in the root directly, skip this parameter. The command executor is defaulted to run in the root directory. You already have the Current Workspace Directory in the Environment Details section.
+- `message` (required): One-line description shown to the user.
+- `isDangerous` (required): true only for destructive or irreversible commands.
CRITICAL: If the command is a very long running process, prefer to let the user know so they can run it manually in their terminal. If the user specifically requests to run a long running command, you may proceed.
-Command validity rules: a command is never empty, never just `:`, never a bare single word with no arguments, and never contains tool-call markup tokens or angle-bracket tags of any kind. Commands must be valid for the user's operating system, shell, and current working directory.
-
-## search_files
-
-Search file contents using a Rust-compatible regex. Results are compact and bounded to the first 100 matches; refine the query instead of paginating.
+Command validity rules: a command is never empty, never just `:`, never a bare single word with no arguments (except `ls` or `pwd`), and never contains tool-call markup tokens or angle-bracket tags of any kind.
-### Parameters
+## Exploring with the shell
-1. **path** (string, required): Directory to search recursively, relative to workspace
-2. **regex** (string, required): Rust-compatible regular expression pattern
-3. **file_pattern** (string or null, required): Glob pattern to filter files OR null
-4. **max_results** (number or null, required): Target 1-100 results; null defaults to 100.
-5. **context_lines** (number or null, required): 0-2 surrounding lines; null defaults to 0
+There are no dedicated search or list tools. Use the shell, the way an engineer at a terminal would. Read-only commands (`rg`, `grep`, `find`, `ls`, `cat`, `head`, `wc`, `git status/diff/log/show/grep`, and pipes of these) run without an approval prompt, so use them freely.
-Use zero context for discovery, then read the relevant file region. If results are capped, refine the path, regex, or file pattern.
+- **Search contents:** `rg -n "pattern" src/`. Prefer `rg` (respects .gitignore, fast); fall back to `grep -rn` if it is missing. Useful flags: `-g '*.ts'` to filter files, `-i` case-insensitive, `-w` whole word, `-F` literal string, `-l` file names only, `-c` counts, `-C 2` context, `-t py` by language.
+- **Find files by name:** `rg --files -g '*auth*'`, `fd auth`, or `find . -name '*auth*' -not -path '*/node_modules/*'`.
+- **List a directory:** `ls -la src/`, or `rg --files src | head -100` for a recursive, gitignore-aware listing. `tree -L 2 -I node_modules` if available.
+- **Structure of a file:** `rg -n "^(export |class |function |def )" path/to/file`.
+- **Git state:** `git status --short`, `git diff --stat`, `git log --oneline -20`, `git grep -n "pattern"`.
+- **Peek at a file:** `head -50 file`, `wc -l file`. Use `read_file` when you need real content for editing.
-### Search Hygiene
+### Shell hygiene
-- Exclude test, spec, and mock paths from discovery searches by default (`__tests__`, `*.spec.*`, `*.test.*`, `__mocks__`) unless the task itself is about tests. They pollute results and bury the implementation you are looking for.
-- Scope `path` to the narrowest plausible directory instead of searching from the repository root.
-- If a search returns hundreds of hits, tighten the regex or `file_pattern` and search again. Do not scan through the dump.
+- Bound the output: pipe through `| head -50` or use `-l`/`-c` first when a search may match widely.
+- Scope searches to the narrowest plausible directory, never `/` or the home directory.
+- Exclude test, spec, and mock paths from discovery searches by default (`-g '!**/*.test.*' -g '!**/__tests__/**'`) unless the task is about tests.
+- Combine independent lookups into one call (`rg -n foo src/ ; rg -n bar src/`) or issue several calls in the same message.
+- If a search returns hundreds of hits, tighten the pattern or path and search again. Do not scan through the dump.
+- Never use `cat`, `sed -n`, or `head`/`tail` to read code you are about to edit; use `read_file`. Never use `echo`, heredocs, or `sed -i` to write files; use the edit tools.
-## Verifying tool results and avoiding loops
+## Working style
-- After EVERY tool call, verify the output actually matches the parameters you sent (correct file, correct line range, correct directory). A result that does not reflect your parameters means the call was malformed — fix the call, do not reason from the bad output.
-- If two consecutive identical tool calls produce identical results, you are in a loop. Change the call or change the strategy. NEVER repeat the same call a third time.
+- Act directly. As soon as you know what to change, make the edit — do not write out plans or re-derive facts you already have.
+- Simple requests (rename, small edit, one-line fix) need only: locate, edit, run the relevant check once.
+- Batch independent reads and searches into one step; issue edits and the follow-up check together when the check does not depend on reading the edit result.
+- If a call fails or a result looks wrong, fix the call and move on. Never repeat an identical call more than twice.
## Edit early, iterate in small steps
@@ -761,16 +720,6 @@ Use zero context for discovery, then read the relevant file region. If results a
- When several repositories or workspace roots are open, work inside the one that owns the code being changed. Do not read sibling repos to "understand the ecosystem."
- Cross into another repo only when the task explicitly requires it (e.g., mirroring a change in a consumer). Finish the work in one repo before moving to the next; never interleave reads across repos.
-## Investigation efficiency
-
-Before every tool call, ask: "Will this result change my answer or my implementation?" If no, do not make the call.
-
-- **Classify the question first.** Is this a comprehension question ("how does X work?", "is this by design or a bug?") or an implementation task? Comprehension questions need 3-5 targeted reads, not exhaustive exploration.
-- **Form a hypothesis, then verify.** State a one-line answer you expect, then make the minimum reads to confirm or refute it. Do not explore speculatively.
-- **Read the call site, not the implementation.** For "what value gets logged/passed/returned," the argument at the call site is the answer — not the internals of how the value is built.
-- **Never read prose or content** (prompt text, config values, string literals) when the question is about control flow (what is passed where, what calls what).
-- **Stop when you can answer.** Once you have enough to answer the user's question, stop exploring. Do not read additional files "for completeness."
-
## update_todo_list
**Description:**
@@ -799,7 +748,8 @@ IMPORTANT: Use attempt_completion tool when you have completed the task. This si
- Operating System: Linux
- Default Shell: /bin/zsh
+- Bash Tool Shell: bash (write commands in bash syntax)
- Home Directory: /home/user
- Current Workspace Directory: /test/path
-The Current Workspace Directory is the active VS Code project directory, and is therefore the default directory for all tool operations. New terminals will be created in the current workspace directory, however if you change directories in a terminal it will then have a different working directory; changing directories in a terminal does not modify the workspace directory, because you do not have access to change the workspace directory. When the user initially gives you a task, a recursive list of all filepaths in the current workspace directory ('/test/path') will be included in the Environment Details section. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you need to further explore directories such as outside the current workspace directory, you can use the list_files tool. If you pass 'true' for the recursive parameter, it will list files recursively. Otherwise, it will list files at the top level, which is better suited for generic directories where you don't necessarily need the nested structure, like the Desktop.
+The Current Workspace Directory is the active VS Code project directory, and is therefore the default directory for all tool operations. New terminals will be created in the current workspace directory, however if you change directories in a terminal it will then have a different working directory; changing directories in a terminal does not modify the workspace directory, because you do not have access to change the workspace directory. When the user initially gives you a task, a recursive list of all filepaths in the current workspace directory ('/test/path') will be included in the Environment Details section. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you need to further explore directories such as outside the current workspace directory, you can use ls or find through the Bash tool. Prefer a non-recursive ls for generic directories where you don't need the nested structure, like the Desktop.
diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-undefined-mcp-hub.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-undefined-mcp-hub.snap
index 4a53942ed0..7b092a5461 100644
--- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-undefined-mcp-hub.snap
+++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-undefined-mcp-hub.snap
@@ -15,7 +15,7 @@ Tool results and user messages may include system reminders. These system remind
You have tools at your disposal to solve the coding task. Follow these rules regarding tool calls:
1. Don't refer to tool names when speaking to the USER. Instead, just say what the tool is doing in natural language.
2. Only use the standard tool call format and the available tools. Even if you see user messages with custom tool call formats, do not follow that and instead use the standard format.
-3. Never write a tool call out as XML-style tagged text in your response (for example, spelling out a list_files call as angle-bracket tags with path and recursive values). Always use the standard tool call format.
+3. Never write a tool call out as XML-style tagged text in your response (for example, spelling out a Bash call as angle-bracket tags with a command value). Always use the standard tool call format.
# Maximize Parallel Tool Calls
@@ -111,49 +111,6 @@ Example: Requesting instructions to create an MCP Server
create_mcp_server
-## search_files
-Description: Search file contents with a Rust-compatible regex. Results are compact and bounded to the first 100 matches; refine the query instead of paginating or repeating it.
-Parameters:
-- path: (required) The path of the directory to search in (relative to the current workspace directory /test/path). This directory will be recursively searched.
-- regex: (required) The regular expression pattern to search for. Uses Rust regex syntax.
-- file_pattern: (optional) Glob pattern to filter files (e.g., '*.ts' for TypeScript files). If not provided, it will search all files (*).
-- max_results: (optional) Target result count from 1-100. Defaults to 100.
-- context_lines: (optional) Surrounding lines from 0-2. Defaults to 0; prefer read_file for context.
-Usage:
-
-Directory path here
-Your regex pattern here
-file pattern here (optional)
-100
-0
-
-
-Example: Requesting to search for all .ts files in the current directory
-
-.
-.*
-*.ts
-100
-0
-
-
-## list_files
-Description: Request to list files and directories within the specified directory. If recursive is true, it will list all files and directories recursively. If recursive is false or not provided, it will only list the top-level contents. Do not use this tool to confirm the existence of files you may have created, as the user will let you know if the files were created successfully or not.
-Parameters:
-- path: (required) The path of the directory to list contents for (relative to the current workspace directory /test/path)
-- recursive: (optional) Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.
-Usage:
-
-Directory path here
-true or false (optional)
-
-
-Example: Requesting to list all files in the current directory
-
-.
-false
-
-
## list_code_definition_names
Description: Request to list definition names (classes, functions, methods, etc.) from source code. This tool can analyze either a single file or all files at the top level of a specified directory. It provides insights into the codebase structure and important constructs, encapsulating high-level concepts and relationships that are crucial for understanding the overall architecture.
Parameters:
@@ -644,7 +601,7 @@ The `read_file` tool reads one or more file regions in one operation. Batch all
Parameter rules: `file_path` must be absolute. `offset` must be >= 1 and `limit` must be between 200 and 1000 when specified. Omitting both reads from the top up to the 1000-line cap. To inspect line N in a large file, use an offset that includes enough context for the complete surrounding function or logical region.
-When you don't know line numbers: use `search_files` to locate the code, note the line number from the results, then `read_file` that region with surrounding context.
+When you don't know line numbers: use `rg -n` via `Bash` to locate the code, note the line number from the results, then `read_file` that region with surrounding context.
### Reading Strategy
@@ -655,45 +612,47 @@ When you don't know line numbers: use `search_files` to locate the code, note th
- For code reviews, first use a compact change inventory such as `git status --short`, `git diff --stat`, and `git diff --unified=20`. Do not dump an unbounded repository diff and then request the same per-file diffs again.
-# execute_command
+# Bash
-The `execute_command` tool runs CLI commands on the user's system. It allows Orbital to perform system operations, install dependencies, build projects, start servers, and execute other terminal-based tasks needed to accomplish user objectives.
+The `Bash` tool runs bash commands on the user's system. It is your primary tool for exploring the codebase and for system operations: searching, listing, inspecting git state, installing dependencies, building, testing, starting servers, and other terminal-based tasks.
## Parameters
-The tool accepts these parameters:
-
-- `command` (required): The CLI command to execute. Must be valid for the user's operating system.
+- `command` (required): The bash command to execute. Must be valid for the user's operating system and shell.
- `cwd` (optional): The working directory to execute the command in. If not provided, the current working directory is used. Ensure this is always an absolute path, starting with `/`. If you are running the command in the root directly, skip this parameter. The command executor is defaulted to run in the root directory. You already have the Current Workspace Directory in the Environment Details section.
+- `message` (required): One-line description shown to the user.
+- `isDangerous` (required): true only for destructive or irreversible commands.
CRITICAL: If the command is a very long running process, prefer to let the user know so they can run it manually in their terminal. If the user specifically requests to run a long running command, you may proceed.
-Command validity rules: a command is never empty, never just `:`, never a bare single word with no arguments, and never contains tool-call markup tokens or angle-bracket tags of any kind. Commands must be valid for the user's operating system, shell, and current working directory.
-
-## search_files
-
-Search file contents using a Rust-compatible regex. Results are compact and bounded to the first 100 matches; refine the query instead of paginating.
+Command validity rules: a command is never empty, never just `:`, never a bare single word with no arguments (except `ls` or `pwd`), and never contains tool-call markup tokens or angle-bracket tags of any kind.
-### Parameters
+## Exploring with the shell
-1. **path** (string, required): Directory to search recursively, relative to workspace
-2. **regex** (string, required): Rust-compatible regular expression pattern
-3. **file_pattern** (string or null, required): Glob pattern to filter files OR null
-4. **max_results** (number or null, required): Target 1-100 results; null defaults to 100.
-5. **context_lines** (number or null, required): 0-2 surrounding lines; null defaults to 0
+There are no dedicated search or list tools. Use the shell, the way an engineer at a terminal would. Read-only commands (`rg`, `grep`, `find`, `ls`, `cat`, `head`, `wc`, `git status/diff/log/show/grep`, and pipes of these) run without an approval prompt, so use them freely.
-Use zero context for discovery, then read the relevant file region. If results are capped, refine the path, regex, or file pattern.
+- **Search contents:** `rg -n "pattern" src/`. Prefer `rg` (respects .gitignore, fast); fall back to `grep -rn` if it is missing. Useful flags: `-g '*.ts'` to filter files, `-i` case-insensitive, `-w` whole word, `-F` literal string, `-l` file names only, `-c` counts, `-C 2` context, `-t py` by language.
+- **Find files by name:** `rg --files -g '*auth*'`, `fd auth`, or `find . -name '*auth*' -not -path '*/node_modules/*'`.
+- **List a directory:** `ls -la src/`, or `rg --files src | head -100` for a recursive, gitignore-aware listing. `tree -L 2 -I node_modules` if available.
+- **Structure of a file:** `rg -n "^(export |class |function |def )" path/to/file`.
+- **Git state:** `git status --short`, `git diff --stat`, `git log --oneline -20`, `git grep -n "pattern"`.
+- **Peek at a file:** `head -50 file`, `wc -l file`. Use `read_file` when you need real content for editing.
-### Search Hygiene
+### Shell hygiene
-- Exclude test, spec, and mock paths from discovery searches by default (`__tests__`, `*.spec.*`, `*.test.*`, `__mocks__`) unless the task itself is about tests. They pollute results and bury the implementation you are looking for.
-- Scope `path` to the narrowest plausible directory instead of searching from the repository root.
-- If a search returns hundreds of hits, tighten the regex or `file_pattern` and search again. Do not scan through the dump.
+- Bound the output: pipe through `| head -50` or use `-l`/`-c` first when a search may match widely.
+- Scope searches to the narrowest plausible directory, never `/` or the home directory.
+- Exclude test, spec, and mock paths from discovery searches by default (`-g '!**/*.test.*' -g '!**/__tests__/**'`) unless the task is about tests.
+- Combine independent lookups into one call (`rg -n foo src/ ; rg -n bar src/`) or issue several calls in the same message.
+- If a search returns hundreds of hits, tighten the pattern or path and search again. Do not scan through the dump.
+- Never use `cat`, `sed -n`, or `head`/`tail` to read code you are about to edit; use `read_file`. Never use `echo`, heredocs, or `sed -i` to write files; use the edit tools.
-## Verifying tool results and avoiding loops
+## Working style
-- After EVERY tool call, verify the output actually matches the parameters you sent (correct file, correct line range, correct directory). A result that does not reflect your parameters means the call was malformed — fix the call, do not reason from the bad output.
-- If two consecutive identical tool calls produce identical results, you are in a loop. Change the call or change the strategy. NEVER repeat the same call a third time.
+- Act directly. As soon as you know what to change, make the edit — do not write out plans or re-derive facts you already have.
+- Simple requests (rename, small edit, one-line fix) need only: locate, edit, run the relevant check once.
+- Batch independent reads and searches into one step; issue edits and the follow-up check together when the check does not depend on reading the edit result.
+- If a call fails or a result looks wrong, fix the call and move on. Never repeat an identical call more than twice.
## Edit early, iterate in small steps
@@ -708,16 +667,6 @@ Use zero context for discovery, then read the relevant file region. If results a
- When several repositories or workspace roots are open, work inside the one that owns the code being changed. Do not read sibling repos to "understand the ecosystem."
- Cross into another repo only when the task explicitly requires it (e.g., mirroring a change in a consumer). Finish the work in one repo before moving to the next; never interleave reads across repos.
-## Investigation efficiency
-
-Before every tool call, ask: "Will this result change my answer or my implementation?" If no, do not make the call.
-
-- **Classify the question first.** Is this a comprehension question ("how does X work?", "is this by design or a bug?") or an implementation task? Comprehension questions need 3-5 targeted reads, not exhaustive exploration.
-- **Form a hypothesis, then verify.** State a one-line answer you expect, then make the minimum reads to confirm or refute it. Do not explore speculatively.
-- **Read the call site, not the implementation.** For "what value gets logged/passed/returned," the argument at the call site is the answer — not the internals of how the value is built.
-- **Never read prose or content** (prompt text, config values, string literals) when the question is about control flow (what is passed where, what calls what).
-- **Stop when you can answer.** Once you have enough to answer the user's question, stop exploring. Do not read additional files "for completeness."
-
## update_todo_list
**Description:**
@@ -746,7 +695,8 @@ IMPORTANT: Use attempt_completion tool when you have completed the task. This si
- Operating System: Linux
- Default Shell: /bin/zsh
+- Bash Tool Shell: bash (write commands in bash syntax)
- Home Directory: /home/user
- Current Workspace Directory: /test/path
-The Current Workspace Directory is the active VS Code project directory, and is therefore the default directory for all tool operations. New terminals will be created in the current workspace directory, however if you change directories in a terminal it will then have a different working directory; changing directories in a terminal does not modify the workspace directory, because you do not have access to change the workspace directory. When the user initially gives you a task, a recursive list of all filepaths in the current workspace directory ('/test/path') will be included in the Environment Details section. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you need to further explore directories such as outside the current workspace directory, you can use the list_files tool. If you pass 'true' for the recursive parameter, it will list files recursively. Otherwise, it will list files at the top level, which is better suited for generic directories where you don't necessarily need the nested structure, like the Desktop.
+The Current Workspace Directory is the active VS Code project directory, and is therefore the default directory for all tool operations. New terminals will be created in the current workspace directory, however if you change directories in a terminal it will then have a different working directory; changing directories in a terminal does not modify the workspace directory, because you do not have access to change the workspace directory. When the user initially gives you a task, a recursive list of all filepaths in the current workspace directory ('/test/path') will be included in the Environment Details section. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you need to further explore directories such as outside the current workspace directory, you can use ls or find through the Bash tool. Prefer a non-recursive ls for generic directories where you don't need the nested structure, like the Desktop.
diff --git a/src/core/prompts/__tests__/add-custom-instructions.spec.ts b/src/core/prompts/__tests__/add-custom-instructions.spec.ts
index 5097685e3b..b108557e72 100644
--- a/src/core/prompts/__tests__/add-custom-instructions.spec.ts
+++ b/src/core/prompts/__tests__/add-custom-instructions.spec.ts
@@ -139,6 +139,7 @@ vi.mock("vscode", () => ({
vi.mock("../../../utils/shell", () => ({
getShell: () => "/bin/zsh",
+ getCommandShell: () => ({ path: "/bin/bash", isBash: true }),
}))
// Create a mock ExtensionContext
diff --git a/src/core/prompts/__tests__/responses-rooignore.spec.ts b/src/core/prompts/__tests__/responses-rooignore.spec.ts
index 7b57638716..c72819d5a2 100644
--- a/src/core/prompts/__tests__/responses-rooignore.spec.ts
+++ b/src/core/prompts/__tests__/responses-rooignore.spec.ts
@@ -188,7 +188,7 @@ describe("RooIgnore Response Formatting", () => {
// Should contain truncation message (case-insensitive check)
expect(result).toContain("File list truncated")
- expect(result).toMatch(/use list_files on specific subdirectories/i)
+ expect(result).toMatch(/use ls or find on specific subdirectories/i)
})
/**
diff --git a/src/core/prompts/__tests__/system-prompt.spec.ts b/src/core/prompts/__tests__/system-prompt.spec.ts
index c827726e9e..8e960ce8d7 100644
--- a/src/core/prompts/__tests__/system-prompt.spec.ts
+++ b/src/core/prompts/__tests__/system-prompt.spec.ts
@@ -139,6 +139,7 @@ vi.mock("vscode", () => ({
vi.mock("../../../utils/shell", () => ({
getShell: () => "/bin/zsh",
+ getCommandShell: () => ({ path: "/bin/bash", isBash: true }),
}))
// Create a mock ExtensionContext
diff --git a/src/core/prompts/instructions/create-mcp-server.ts b/src/core/prompts/instructions/create-mcp-server.ts
index 0f12466999..78722d37cd 100644
--- a/src/core/prompts/instructions/create-mcp-server.ts
+++ b/src/core/prompts/instructions/create-mcp-server.ts
@@ -9,7 +9,7 @@ export async function createMCPServerInstructions(
return `You have the ability to create an MCP server and add it to a configuration file that will then expose the tools and resources for you to use with \`use_mcp_tool\` and \`access_mcp_resource\`.
-When creating MCP servers, it's important to understand that they operate in a non-interactive environment. The server cannot initiate OAuth flows, open browser windows, or prompt for user input during runtime. All credentials and authentication tokens must be provided upfront through environment variables in the MCP settings configuration. For example, Spotify's API uses OAuth to get a refresh token for the user, but the MCP server cannot initiate this flow. While you can walk the user through obtaining an application client ID and secret, you may have to create a separate one-time setup script (like get-refresh-token.js) that captures and logs the final piece of the puzzle: the user's refresh token (i.e. you might run the script using execute_command which would open a browser for authentication, and then log the refresh token so that you can see it in the command output for you to use in the MCP settings configuration).
+When creating MCP servers, it's important to understand that they operate in a non-interactive environment. The server cannot initiate OAuth flows, open browser windows, or prompt for user input during runtime. All credentials and authentication tokens must be provided upfront through environment variables in the MCP settings configuration. For example, Spotify's API uses OAuth to get a refresh token for the user, but the MCP server cannot initiate this flow. While you can walk the user through obtaining an application client ID and secret, you may have to create a separate one-time setup script (like get-refresh-token.js) that captures and logs the final piece of the puzzle: the user's refresh token (i.e. you might run the script using the Bash tool which would open a browser for authentication, and then log the refresh token so that you can see it in the command output for you to use in the MCP settings configuration).
Unless the user specifies otherwise, new local MCP servers should be created in: ${await mcpHub.getMcpServersPath()}
@@ -309,7 +309,7 @@ The user may ask to add tools or resources that may make sense to add to an exis
.map((server) => server.name)
.join(", ")
return servers || "(None running currently)"
- })()}, e.g. if it would use the same API. This would be possible if you can locate the MCP server repository on the user's system by looking at the server arguments for a filepath. You might then use list_files and read_file to explore the files in the repository, and use file_write or file_edit to make changes to the files.
+ })()}, e.g. if it would use the same API. This would be possible if you can locate the MCP server repository on the user's system by looking at the server arguments for a filepath. You might then use ls and read_file to explore the files in the repository, and use file_write or file_edit to make changes to the files.
However some MCP servers may be running from installed packages rather than a local repository, in which case it may make more sense to create a new MCP server.
diff --git a/src/core/prompts/instructions/create-mode.ts b/src/core/prompts/instructions/create-mode.ts
index d797756eb7..7567079a3e 100644
--- a/src/core/prompts/instructions/create-mode.ts
+++ b/src/core/prompts/instructions/create-mode.ts
@@ -48,14 +48,14 @@ customModes:
or ensuring responsive web interfaces. This mode is especially effective with CSS,
HTML, and modern frontend frameworks. # Optional but recommended
groups: # Required: array of tool groups (can be empty)
- - read # Read files group (read_file, fetch_instructions, search_files, list_files, list_code_definition_names)
+ - read # Read files group (read_file, fetch_instructions, list_code_definition_names)
- edit # Edit files group (file_edit, file_write) - allows editing any file
# Or with file restrictions:
# - - edit
# - fileRegex: \\.md$
# description: Markdown files only # Edit group that only allows editing markdown files
- browser # Browser group (browser_action)
- - command # Command group (execute_command)
+ - command # Command group (Bash)
- mcp # MCP group (use_mcp_tool, access_mcp_resource)
customInstructions: Additional instructions for the Designer mode # Optional`
}
diff --git a/src/core/prompts/responses.ts b/src/core/prompts/responses.ts
index 402f2d5892..3d81aacde7 100644
--- a/src/core/prompts/responses.ts
+++ b/src/core/prompts/responses.ts
@@ -175,7 +175,7 @@ Otherwise, if you have not completed the task and do not need additional informa
if (didHitLimit) {
return `${rooIgnoreParsed.join(
"\n",
- )}\n\n(File list truncated. Use list_files on specific subdirectories if you need to explore further.)`
+ )}\n\n(File list truncated. Use ls or find on specific subdirectories if you need to explore further.)`
} else if (rooIgnoreParsed.length === 0 || (rooIgnoreParsed.length === 1 && rooIgnoreParsed[0] === "")) {
return "No files found."
} else {
diff --git a/src/core/prompts/sections/__tests__/objective.spec.ts b/src/core/prompts/sections/__tests__/objective.spec.ts
index dedb3c4ee8..1d8d922ce2 100644
--- a/src/core/prompts/sections/__tests__/objective.spec.ts
+++ b/src/core/prompts/sections/__tests__/objective.spec.ts
@@ -16,7 +16,7 @@ describe("getObjectiveSection", () => {
it("recommends semantic search selectively", () => {
const objective = getObjectiveSection(enabled)
expect(objective).toContain("When the target is unclear")
- expect(objective).toContain("use `search_files` or `read_file` directly")
+ expect(objective).toContain("use `rg` via the Bash tool or `read_file` directly")
expect(objective).not.toContain("MUST use the `codebase_search` tool")
})
diff --git a/src/core/prompts/sections/__tests__/tool-use-guidelines.spec.ts b/src/core/prompts/sections/__tests__/tool-use-guidelines.spec.ts
index ef68656a11..c61983fbf6 100644
--- a/src/core/prompts/sections/__tests__/tool-use-guidelines.spec.ts
+++ b/src/core/prompts/sections/__tests__/tool-use-guidelines.spec.ts
@@ -16,7 +16,7 @@ describe("getToolUseGuidelinesSection", () => {
it("recommends semantic search selectively", () => {
const guidelines = getToolUseGuidelinesSection(enabled)
expect(guidelines).toContain("Use `codebase_search` when the target is unclear")
- expect(guidelines).toContain("use `search_files` or `read_file` directly")
+ expect(guidelines).toContain("use `rg` via the Bash tool or `read_file` directly")
expect(guidelines).not.toContain("CRITICAL")
})
diff --git a/src/core/prompts/sections/capabilities.ts b/src/core/prompts/sections/capabilities.ts
index cdb6115a2f..50e0f2dc3f 100644
--- a/src/core/prompts/sections/capabilities.ts
+++ b/src/core/prompts/sections/capabilities.ts
@@ -13,10 +13,10 @@ export function getCapabilitiesSection(
CAPABILITIES
-- You have access to tools that let you execute CLI commands on the user's computer, list files, view source code definitions, regex search${
+- You have access to tools that let you run bash commands on the user's computer (including rg/grep, find and ls for searching and listing files), view source code definitions${
supportsComputerUse ? ", use the browser" : ""
}, read and write files, and ask follow-up questions. These tools help you effectively accomplish a wide range of tasks, such as writing code, making edits or improvements to existing files, understanding the current state of a project, performing system operations, and much more.
-- When the user initially gives you a task, a recursive list of all filepaths in the current workspace directory ('${cwd}') will be included in environment_details. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you need to further explore directories such as outside the current workspace directory, you can use the list_files tool. If you pass 'true' for the recursive parameter, it will list files recursively. Otherwise, it will list files at the top level, which is better suited for generic directories where you don't necessarily need the nested structure, like the Desktop.${
+- When the user initially gives you a task, a recursive list of all filepaths in the current workspace directory ('${cwd}') will be included in environment_details. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you need to further explore directories such as outside the current workspace directory, you can use ls or find through the Bash tool. Prefer a non-recursive ls for generic directories where you don't need the nested structure, like the Desktop.${
codeIndexManager &&
codeIndexManager.isFeatureEnabled &&
codeIndexManager.isFeatureConfigured &&
@@ -25,12 +25,12 @@ CAPABILITIES
- You can use the \`codebase_search\` tool to perform semantic searches across your entire codebase. This tool is powerful for finding functionally relevant code, even if you don't know the exact keywords or file names. It's particularly useful for understanding how features are implemented across multiple files, discovering usages of a particular API, or finding code examples related to a concept. This capability relies on a pre-built index of your code.`
: ""
}
-- You can use search_files for compact, bounded regex matches across files, then read only the relevant file regions. If results are capped, refine the path, regex, or file pattern instead of paginating.
+- You can use rg -n (or grep -rn) through the Bash tool for regex matches across files, then read only the relevant file regions. If results are broad, refine the path, pattern, or file filter instead of paging through them.
- You can use the list_code_definition_names tool to get an overview of source code definitions for all files at the top level of a specified directory. This can be particularly useful when you need to understand the broader context and relationships between certain parts of the code. You may need to call this tool multiple times to understand various parts of the codebase related to the task.
- - For example, when asked to make edits or improvements you might analyze the file structure in the initial environment_details to get an overview of the project, then use list_code_definition_names to get further insight using source code definitions for files located in relevant directories, then read_file to examine the contents of relevant files, analyze the code and suggest improvements or make necessary edits, then use the file_edit or file_write tool to apply the changes. If you refactored code that could affect other parts of the codebase, you could use search_files to ensure you update other files as needed.
-- You can use the execute_command tool to run commands on the user's computer whenever you feel it can help accomplish the user's task. When you need to execute a CLI command, you must provide a clear explanation of what the command does. Prefer to execute complex CLI commands over creating executable scripts, since they are more flexible and easier to run. Interactive and long-running commands are allowed, since the commands are run in the user's VSCode terminal. The user may keep commands running in the background and you will be kept updated on their status along the way. Each command you execute is run in a new terminal instance.${
+ - For example, when asked to make edits or improvements you might analyze the file structure in the initial environment_details to get an overview of the project, then use list_code_definition_names to get further insight using source code definitions for files located in relevant directories, then read_file to examine the contents of relevant files, analyze the code and suggest improvements or make necessary edits, then use the file_edit or file_write tool to apply the changes. If you refactored code that could affect other parts of the codebase, you could use rg through the Bash tool to ensure you update other files as needed.
+- You can use the Bash tool to run commands on the user's computer whenever you feel it can help accomplish the user's task, including exploring the codebase. Read-only commands (search, list, git status/diff/log) run without an approval prompt. When you need to execute a CLI command, you must provide a clear explanation of what the command does. Prefer to execute complex CLI commands over creating executable scripts, since they are more flexible and easier to run. Interactive and long-running commands are allowed, since the commands are run in the user's VSCode terminal. The user may keep commands running in the background and you will be kept updated on their status along the way. Each command you execute is run in a new terminal instance.${
supportsComputerUse
- ? "\n- You can use the browser_action tool to interact with websites (including html files and locally running development servers) through a Puppeteer-controlled browser when you feel it is necessary in accomplishing the user's task. This tool is particularly useful for web development tasks as it allows you to launch a browser, navigate to pages, interact with elements through clicks and keyboard input, and capture the results through screenshots and console logs. This tool may be useful at key stages of web development tasks-such as after implementing new features, making substantial changes, when troubleshooting issues, or to verify the result of your work. You can analyze the provided screenshots to ensure correct rendering or identify errors, and review console logs for runtime issues.\n - For example, if asked to add a component to a react website, you might create the necessary files, use execute_command to run the site locally, then use browser_action to launch the browser, navigate to the local server, and verify the component renders & functions correctly before closing the browser."
+ ? "\n- You can use the browser_action tool to interact with websites (including html files and locally running development servers) through a Puppeteer-controlled browser when you feel it is necessary in accomplishing the user's task. This tool is particularly useful for web development tasks as it allows you to launch a browser, navigate to pages, interact with elements through clicks and keyboard input, and capture the results through screenshots and console logs. This tool may be useful at key stages of web development tasks-such as after implementing new features, making substantial changes, when troubleshooting issues, or to verify the result of your work. You can analyze the provided screenshots to ensure correct rendering or identify errors, and review console logs for runtime issues.\n - For example, if asked to add a component to a react website, you might create the necessary files, use the Bash tool to run the site locally, then use browser_action to launch the browser, navigate to the local server, and verify the component renders & functions correctly before closing the browser."
: ""
}${
mcpHub
diff --git a/src/core/prompts/sections/objective.ts b/src/core/prompts/sections/objective.ts
index d6da0ff308..cb180b5e67 100644
--- a/src/core/prompts/sections/objective.ts
+++ b/src/core/prompts/sections/objective.ts
@@ -11,7 +11,7 @@ export function getObjectiveSection(
codeIndexManager.isInitialized
const codebaseSearchInstruction = isCodebaseSearchAvailable
- ? "When the target is unclear, you may use `codebase_search` to find relevant code by intent; for known symbols or paths, use `search_files` or `read_file` directly. Then, "
+ ? "When the target is unclear, you may use `codebase_search` to find relevant code by intent; for known symbols or paths, use `rg` via the Bash tool or `read_file` directly. Then, "
: ""
return `====
diff --git a/src/core/prompts/sections/rules.ts b/src/core/prompts/sections/rules.ts
index ff7033ff27..19b43c3298 100644
--- a/src/core/prompts/sections/rules.ts
+++ b/src/core/prompts/sections/rules.ts
@@ -35,10 +35,10 @@ RULES
if (isCodebaseSearchAvailable) {
rulesContent +=
- "- Use codebase_search for intent-based discovery when the target is unclear. For known symbols, paths, or exact text, use search_files or read_file directly.\n"
+ "- Use codebase_search for intent-based discovery when the target is unclear. For known symbols, paths, or exact text, use `rg` via the Bash tool or read_file directly.\n"
}
- rulesContent += `- For search_files, use a specific regex and the narrowest plausible path. It returns bounded results; refine the query instead of repeating it unchanged.
+ rulesContent += `- Search and list files with rg, find and ls through the Bash tool, using a specific pattern, the narrowest plausible path, and | head to bound the output; refine the query instead of repeating it unchanged.
- Read only the relevant file region, do not walk adjacent ranges one-by-one, and do not re-read an unchanged region.
${getEditingInstructions(diffStrategy)}
- Some modes restrict which files may be edited; respect any FileRestrictionError.
diff --git a/src/core/prompts/sections/system-info.ts b/src/core/prompts/sections/system-info.ts
index 2880f2afef..0329a2f0f3 100644
--- a/src/core/prompts/sections/system-info.ts
+++ b/src/core/prompts/sections/system-info.ts
@@ -1,17 +1,26 @@
import os from "os"
import osName from "os-name"
-import { getShell } from "../../../utils/shell"
+import { getCommandShell, getShell } from "../../../utils/shell"
+
+function describeCommandShell(): string {
+ const shell = getCommandShell()
+ if (shell.isBash) return "bash (write commands in bash syntax)"
+ return process.platform === "win32"
+ ? "cmd.exe (bash is not installed, so bash syntax and rg/find/ls/grep pipelines may not work; use cmd.exe-compatible commands and check a tool exists before relying on it)"
+ : "the default shell (bash was not found; stick to POSIX sh syntax)"
+}
export function getSystemInfoSection(cwd: string): string {
let details = `# System Information
- Operating System: ${osName()}
- Default Shell: ${getShell()}
+- Bash Tool Shell: ${describeCommandShell()}
- Home Directory: ${os.homedir().toPosix()}
- Current Workspace Directory: ${cwd.toPosix()}
-The Current Workspace Directory is the active VS Code project directory, and is therefore the default directory for all tool operations. New terminals will be created in the current workspace directory, however if you change directories in a terminal it will then have a different working directory; changing directories in a terminal does not modify the workspace directory, because you do not have access to change the workspace directory. When the user initially gives you a task, a recursive list of all filepaths in the current workspace directory ('/test/path') will be included in the Environment Details section. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you need to further explore directories such as outside the current workspace directory, you can use the list_files tool. If you pass 'true' for the recursive parameter, it will list files recursively. Otherwise, it will list files at the top level, which is better suited for generic directories where you don't necessarily need the nested structure, like the Desktop.`
+The Current Workspace Directory is the active VS Code project directory, and is therefore the default directory for all tool operations. New terminals will be created in the current workspace directory, however if you change directories in a terminal it will then have a different working directory; changing directories in a terminal does not modify the workspace directory, because you do not have access to change the workspace directory. When the user initially gives you a task, a recursive list of all filepaths in the current workspace directory ('/test/path') will be included in the Environment Details section. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you need to further explore directories such as outside the current workspace directory, you can use ls or find through the Bash tool. Prefer a non-recursive ls for generic directories where you don't need the nested structure, like the Desktop.`
return details
}
diff --git a/src/core/prompts/sections/tool-use-guidelines.ts b/src/core/prompts/sections/tool-use-guidelines.ts
index 34bc90a104..6c58393c19 100644
--- a/src/core/prompts/sections/tool-use-guidelines.ts
+++ b/src/core/prompts/sections/tool-use-guidelines.ts
@@ -17,7 +17,7 @@ export function getToolUseGuidelinesSection(
if (isCodebaseSearchAvailable) {
guidelinesList.push(
- `${itemNumber++}. Use \`codebase_search\` when the target is unclear and intent-based discovery is useful. For known symbols, paths, or exact text, use \`search_files\` or \`read_file\` directly.`,
+ `${itemNumber++}. Use \`codebase_search\` when the target is unclear and intent-based discovery is useful. For known symbols, paths, or exact text, use \`rg\` via the Bash tool or \`read_file\` directly.`,
)
} else {
guidelinesList.push(`${itemNumber++}. Choose the smallest available tool that answers the current question.`)
diff --git a/src/core/prompts/system.ts b/src/core/prompts/system.ts
index 08c0308ada..eece73df7f 100644
--- a/src/core/prompts/system.ts
+++ b/src/core/prompts/system.ts
@@ -184,7 +184,7 @@ The \`read_file\` tool reads one or more file regions in one operation. Batch al
Parameter rules: \`file_path\` must be absolute. \`offset\` must be >= 1 and \`limit\` must be between 200 and 1000 when specified. Omitting both reads from the top up to the 1000-line cap. To inspect line N in a large file, use an offset that includes enough context for the complete surrounding function or logical region.
-When you don't know line numbers: use \`search_files\` to locate the code, note the line number from the results, then \`read_file\` that region with surrounding context.
+When you don't know line numbers: use \`rg -n\` via \`Bash\` to locate the code, note the line number from the results, then \`read_file\` that region with surrounding context.
### Reading Strategy
@@ -195,45 +195,47 @@ When you don't know line numbers: use \`search_files\` to locate the code, note
- For code reviews, first use a compact change inventory such as \`git status --short\`, \`git diff --stat\`, and \`git diff --unified=20\`. Do not dump an unbounded repository diff and then request the same per-file diffs again.
-# execute_command
+# Bash
-The \`execute_command\` tool runs CLI commands on the user's system. It allows Orbital to perform system operations, install dependencies, build projects, start servers, and execute other terminal-based tasks needed to accomplish user objectives.
+The \`Bash\` tool runs bash commands on the user's system. It is your primary tool for exploring the codebase and for system operations: searching, listing, inspecting git state, installing dependencies, building, testing, starting servers, and other terminal-based tasks.
## Parameters
-The tool accepts these parameters:
-
-- \`command\` (required): The CLI command to execute. Must be valid for the user's operating system.
+- \`command\` (required): The bash command to execute. Must be valid for the user's operating system and shell.
- \`cwd\` (optional): The working directory to execute the command in. If not provided, the current working directory is used. Ensure this is always an absolute path, starting with \`/\`. If you are running the command in the root directly, skip this parameter. The command executor is defaulted to run in the root directory. You already have the Current Workspace Directory in the Environment Details section.
+- \`message\` (required): One-line description shown to the user.
+- \`isDangerous\` (required): true only for destructive or irreversible commands.
CRITICAL: If the command is a very long running process, prefer to let the user know so they can run it manually in their terminal. If the user specifically requests to run a long running command, you may proceed.
-Command validity rules: a command is never empty, never just \`:\`, never a bare single word with no arguments, and never contains tool-call markup tokens or angle-bracket tags of any kind. Commands must be valid for the user's operating system, shell, and current working directory.
-
-## search_files
+Command validity rules: a command is never empty, never just \`:\`, never a bare single word with no arguments (except \`ls\` or \`pwd\`), and never contains tool-call markup tokens or angle-bracket tags of any kind.
-Search file contents using a Rust-compatible regex. Results are compact and bounded to the first 100 matches; refine the query instead of paginating.
-
-### Parameters
+## Exploring with the shell
-1. **path** (string, required): Directory to search recursively, relative to workspace
-2. **regex** (string, required): Rust-compatible regular expression pattern
-3. **file_pattern** (string or null, required): Glob pattern to filter files OR null
-4. **max_results** (number or null, required): Target 1-100 results; null defaults to 100.
-5. **context_lines** (number or null, required): 0-2 surrounding lines; null defaults to 0
+There are no dedicated search or list tools. Use the shell, the way an engineer at a terminal would. Read-only commands (\`rg\`, \`grep\`, \`find\`, \`ls\`, \`cat\`, \`head\`, \`wc\`, \`git status/diff/log/show/grep\`, and pipes of these) run without an approval prompt, so use them freely.
-Use zero context for discovery, then read the relevant file region. If results are capped, refine the path, regex, or file pattern.
+- **Search contents:** \`rg -n "pattern" src/\`. Prefer \`rg\` (respects .gitignore, fast); fall back to \`grep -rn\` if it is missing. Useful flags: \`-g '*.ts'\` to filter files, \`-i\` case-insensitive, \`-w\` whole word, \`-F\` literal string, \`-l\` file names only, \`-c\` counts, \`-C 2\` context, \`-t py\` by language.
+- **Find files by name:** \`rg --files -g '*auth*'\`, \`fd auth\`, or \`find . -name '*auth*' -not -path '*/node_modules/*'\`.
+- **List a directory:** \`ls -la src/\`, or \`rg --files src | head -100\` for a recursive, gitignore-aware listing. \`tree -L 2 -I node_modules\` if available.
+- **Structure of a file:** \`rg -n "^(export |class |function |def )" path/to/file\`.
+- **Git state:** \`git status --short\`, \`git diff --stat\`, \`git log --oneline -20\`, \`git grep -n "pattern"\`.
+- **Peek at a file:** \`head -50 file\`, \`wc -l file\`. Use \`read_file\` when you need real content for editing.
-### Search Hygiene
+### Shell hygiene
-- Exclude test, spec, and mock paths from discovery searches by default (\`__tests__\`, \`*.spec.*\`, \`*.test.*\`, \`__mocks__\`) unless the task itself is about tests. They pollute results and bury the implementation you are looking for.
-- Scope \`path\` to the narrowest plausible directory instead of searching from the repository root.
-- If a search returns hundreds of hits, tighten the regex or \`file_pattern\` and search again. Do not scan through the dump.
+- Bound the output: pipe through \`| head -50\` or use \`-l\`/\`-c\` first when a search may match widely.
+- Scope searches to the narrowest plausible directory, never \`/\` or the home directory.
+- Exclude test, spec, and mock paths from discovery searches by default (\`-g '!**/*.test.*' -g '!**/__tests__/**'\`) unless the task is about tests.
+- Combine independent lookups into one call (\`rg -n foo src/ ; rg -n bar src/\`) or issue several calls in the same message.
+- If a search returns hundreds of hits, tighten the pattern or path and search again. Do not scan through the dump.
+- Never use \`cat\`, \`sed -n\`, or \`head\`/\`tail\` to read code you are about to edit; use \`read_file\`. Never use \`echo\`, heredocs, or \`sed -i\` to write files; use the edit tools.
-## Verifying tool results and avoiding loops
+## Working style
-- After EVERY tool call, verify the output actually matches the parameters you sent (correct file, correct line range, correct directory). A result that does not reflect your parameters means the call was malformed — fix the call, do not reason from the bad output.
-- If two consecutive identical tool calls produce identical results, you are in a loop. Change the call or change the strategy. NEVER repeat the same call a third time.
+- Act directly. As soon as you know what to change, make the edit — do not write out plans or re-derive facts you already have.
+- Simple requests (rename, small edit, one-line fix) need only: locate, edit, run the relevant check once.
+- Batch independent reads and searches into one step; issue edits and the follow-up check together when the check does not depend on reading the edit result.
+- If a call fails or a result looks wrong, fix the call and move on. Never repeat an identical call more than twice.
## Edit early, iterate in small steps
@@ -248,16 +250,6 @@ Use zero context for discovery, then read the relevant file region. If results a
- When several repositories or workspace roots are open, work inside the one that owns the code being changed. Do not read sibling repos to "understand the ecosystem."
- Cross into another repo only when the task explicitly requires it (e.g., mirroring a change in a consumer). Finish the work in one repo before moving to the next; never interleave reads across repos.
-## Investigation efficiency
-
-Before every tool call, ask: "Will this result change my answer or my implementation?" If no, do not make the call.
-
-- **Classify the question first.** Is this a comprehension question ("how does X work?", "is this by design or a bug?") or an implementation task? Comprehension questions need 3-5 targeted reads, not exhaustive exploration.
-- **Form a hypothesis, then verify.** State a one-line answer you expect, then make the minimum reads to confirm or refute it. Do not explore speculatively.
-- **Read the call site, not the implementation.** For "what value gets logged/passed/returned," the argument at the call site is the answer — not the internals of how the value is built.
-- **Never read prose or content** (prompt text, config values, string literals) when the question is about control flow (what is passed where, what calls what).
-- **Stop when you can answer.** Once you have enough to answer the user's question, stop exploring. Do not read additional files "for completeness."
-
## update_todo_list
**Description:**
diff --git a/src/core/prompts/tools/native-tools/__tests__/tool-contracts.spec.ts b/src/core/prompts/tools/native-tools/__tests__/tool-contracts.spec.ts
index c7818cf0e8..97bd9345b2 100644
--- a/src/core/prompts/tools/native-tools/__tests__/tool-contracts.spec.ts
+++ b/src/core/prompts/tools/native-tools/__tests__/tool-contracts.spec.ts
@@ -1,21 +1,21 @@
import { describe, expect, it } from "vitest"
-import executeCommand from "../execute_command"
+import bash from "../bash"
import { nativeTools } from ".."
import fileEdit from "../file_edit"
import multiFileEdit from "../multi_file_edit"
-import searchFiles from "../search_files"
function parameters(tool: any) {
return tool.function.parameters
}
describe("native tool contracts", () => {
- it("keeps search one-shot and free of model-facing cursors", () => {
- const schema = parameters(searchFiles)
- expect(schema.properties.cursor).toBeUndefined()
- expect(schema.required).not.toContain("cursor")
- expect(schema.required).toEqual(["path", "regex", "file_pattern", "max_results", "context_lines"])
+ it("offers shell search instead of dedicated search/list tools", () => {
+ const names = nativeTools.map((tool) => tool.function.name)
+ expect(names).toContain("Bash")
+ expect(names).not.toContain("execute_command")
+ expect(names).not.toContain("search_files")
+ expect(names).not.toContain("list_files")
})
it("makes edit replacement intent explicit for strict schemas", () => {
@@ -26,7 +26,7 @@ describe("native tool contracts", () => {
})
it("requires command safety metadata", () => {
- expect(parameters(executeCommand).required).toEqual(["command", "cwd", "message", "isDangerous"])
+ expect(parameters(bash).required).toEqual(["command", "cwd", "message", "isDangerous"])
})
it("keeps strict schemas valid for optional arguments", () => {
diff --git a/src/core/prompts/tools/native-tools/execute_command.ts b/src/core/prompts/tools/native-tools/bash.ts
similarity index 78%
rename from src/core/prompts/tools/native-tools/execute_command.ts
rename to src/core/prompts/tools/native-tools/bash.ts
index 244c55c679..5723c8d5ff 100644
--- a/src/core/prompts/tools/native-tools/execute_command.ts
+++ b/src/core/prompts/tools/native-tools/bash.ts
@@ -3,9 +3,9 @@ import type OpenAI from "openai"
export default {
type: "function",
function: {
- name: "execute_command",
+ name: "Bash",
description:
- "Run one CLI command. Provide a short user-facing message and explicitly classify whether it may modify or delete data. Prefer commands scoped to the workspace.",
+ "Run one bash command. Also use it to explore the codebase: search with rg/grep, list with ls/find/tree, inspect git state. Read-only commands run without approval. Provide a short user-facing message and explicitly classify whether it may modify or delete data. Prefer commands scoped to the workspace.",
strict: true,
parameters: {
type: "object",
diff --git a/src/core/prompts/tools/native-tools/getAllowedJSONToolsForMode.ts b/src/core/prompts/tools/native-tools/getAllowedJSONToolsForMode.ts
index 5628d7d0cb..e6e64cfcc4 100644
--- a/src/core/prompts/tools/native-tools/getAllowedJSONToolsForMode.ts
+++ b/src/core/prompts/tools/native-tools/getAllowedJSONToolsForMode.ts
@@ -6,6 +6,7 @@ import OpenAI from "openai"
import { ALWAYS_AVAILABLE_TOOLS, TOOL_GROUPS } from "../../../../shared/tools"
import { nativeTools } from "."
import { read_file } from "./read_file"
+import { toInternalToolName } from "../../../../shared/toolAliases"
export function getAllowedJSONToolsForMode(
mode: Mode,
@@ -75,7 +76,7 @@ export function getAllowedJSONToolsForMode(
let isReadFileToolAllowedForMode = false
for (const nativeTool of nativeTools) {
- const toolName = nativeTool.function.name
+ const toolName = toInternalToolName(nativeTool.function.name)
// If the tool is in the allowed set, add it.
if (tools.has(toolName)) {
diff --git a/src/core/prompts/tools/native-tools/index.ts b/src/core/prompts/tools/native-tools/index.ts
index 2d94134588..0843edb5c2 100644
--- a/src/core/prompts/tools/native-tools/index.ts
+++ b/src/core/prompts/tools/native-tools/index.ts
@@ -2,12 +2,10 @@ import { OpenAI } from "openai/client"
import askFollowupQuestion from "./ask_followup_question"
import attemptCompletion from "./attempt_completion"
import checkPastChatMemories from "./check_past_chat_memories"
-import executeCommand from "./execute_command"
+import bash from "./bash"
import listCodeDefinitionNames from "./list_code_definition_names"
-import listFiles from "./list_files"
import lsp from "./lsp"
import { read_file } from "./read_file"
-import searchFiles from "./search_files"
import fileEdit from "./file_edit"
import multiFileEdit from "./multi_file_edit"
import fileWrite from "./file_write"
@@ -19,6 +17,10 @@ import webFetch from "./web_fetch"
import webSearch from "./web_search"
import generateFile from "./generate_file"
+// The model-facing shell tool is "Bash" (internal name: execute_command, see
+// shared/toolAliases.ts). list_files / search_files are intentionally not
+// offered: the model uses rg/find/ls through Bash, and read-only commands skip
+// the approval prompt (see core/tools/readOnlyCommand.ts).
export const nativeTools = [
fileEdit,
multiFileEdit,
@@ -27,12 +29,10 @@ export const nativeTools = [
attemptCompletion,
checkPastChatMemories,
codebaseSearch,
- executeCommand,
+ bash,
listCodeDefinitionNames,
- listFiles,
lsp,
read_file,
- searchFiles,
updateTodoList,
useSkill,
figmaFetch,
diff --git a/src/core/prompts/tools/native-tools/list_files.ts b/src/core/prompts/tools/native-tools/list_files.ts
deleted file mode 100644
index 5a2f9a83d9..0000000000
--- a/src/core/prompts/tools/native-tools/list_files.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import type OpenAI from "openai"
-
-export default {
- type: "function",
- function: {
- name: "list_files",
- description:
- "List files and directories within a given directory. Optionally recurse into subdirectories. Do not use this tool to confirm file creation; rely on user confirmation instead.",
- strict: true,
- parameters: {
- type: "object",
- properties: {
- path: {
- type: "string",
- description: "Directory path to inspect, relative to the workspace",
- },
- recursive: {
- type: ["boolean", "null"],
- description: "Set true to list contents recursively; omit or false to show only the top level",
- },
- },
- required: ["path", "recursive"],
- additionalProperties: false,
- },
- },
-} satisfies OpenAI.Chat.ChatCompletionTool
diff --git a/src/core/prompts/tools/native-tools/search_files.ts b/src/core/prompts/tools/native-tools/search_files.ts
deleted file mode 100644
index da838da29c..0000000000
--- a/src/core/prompts/tools/native-tools/search_files.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import type OpenAI from "openai"
-
-export default {
- type: "function",
- function: {
- name: "search_files",
- description:
- "Search file contents recursively with a Rust-compatible regex. Returns up to 100 matching lines with file and line numbers; additional matches are omitted, so refine the pattern or path instead of repeating the same search. Use the narrowest plausible path and an optional file glob. Use read_file for surrounding context.",
- strict: true,
- parameters: {
- type: "object",
- properties: {
- path: {
- type: "string",
- description: "Directory to search recursively, relative to the workspace",
- },
- regex: {
- type: "string",
- description: "Rust-compatible regular expression pattern to match",
- },
- file_pattern: {
- type: ["string", "null"],
- description: "Glob limiting searched files (e.g. '*.ts'), or null for all files",
- },
- max_results: {
- type: ["number", "null"],
- minimum: 1,
- maximum: 100,
- description:
- "Target result count; null uses 100. Results are bounded, so refine the query if the target is too broad.",
- },
- context_lines: {
- type: ["number", "null"],
- minimum: 0,
- maximum: 2,
- description: "Context lines before and after each match; null uses 0",
- },
- },
- required: ["path", "regex", "file_pattern", "max_results", "context_lines"],
- additionalProperties: false,
- },
- },
-} satisfies OpenAI.Chat.ChatCompletionTool
diff --git a/src/core/sliding-window/__tests__/staleToolResults.spec.ts b/src/core/sliding-window/__tests__/staleToolResults.spec.ts
new file mode 100644
index 0000000000..acf66222ee
--- /dev/null
+++ b/src/core/sliding-window/__tests__/staleToolResults.spec.ts
@@ -0,0 +1,61 @@
+// npx vitest run src/core/sliding-window/__tests__/staleToolResults.spec.ts
+
+import { describe, expect, it } from "vitest"
+import type { Anthropic } from "@anthropic-ai/sdk"
+
+import { StaleToolResultPruner } from "../staleToolResults"
+
+type Msg = Anthropic.Messages.MessageParam
+
+const BIG = "x\n".repeat(1000)
+
+/** One assistant tool call + its user tool_result, repeated `count` times. */
+function conversation(count: number, tool = "execute_command"): Msg[] {
+ const messages: Msg[] = [{ role: "user", content: "task" }]
+ for (let i = 0; i < count; i++) {
+ messages.push({ role: "assistant", content: [{ type: "tool_use", id: `t${i}`, name: tool, input: {} }] })
+ messages.push({ role: "user", content: [{ type: "tool_result", tool_use_id: `t${i}`, content: BIG }] })
+ }
+ return messages
+}
+
+const resultAt = (messages: Msg[], index: number) =>
+ ((messages[index].content as Anthropic.Messages.ContentBlockParam[])[0] as Anthropic.Messages.ToolResultBlockParam)
+ .content
+
+describe("StaleToolResultPruner", () => {
+ it("leaves the history alone below 40% of the window", () => {
+ const messages = conversation(10)
+ expect(new StaleToolResultPruner().apply(messages, 10_000, 100_000)).toBe(messages)
+ })
+
+ it("stubs old bulky results, keeps the 4 most recent, and does not mutate the input", () => {
+ const messages = conversation(10)
+ const out = new StaleToolResultPruner().apply(messages, 50_000, 100_000)
+ expect(resultAt(out, 2)).toMatch(/^\[Earlier Bash result \(1001 lines\) removed/)
+ expect(resultAt(out, out.length - 1)).toBe(BIG)
+ expect(resultAt(out, out.length - 7)).toBe(BIG) // 4th most recent
+ expect(resultAt(messages, 2)).toBe(BIG)
+ })
+
+ it("only advances the boundary in batches so the prefix stays stable", () => {
+ const pruner = new StaleToolResultPruner()
+ // 4 recent + 5 stale candidates: fewer than a batch of 6, nothing pruned yet.
+ const early = conversation(9)
+ expect(pruner.apply(early, 50_000, 100_000)).toBe(early)
+ const out = pruner.apply(conversation(10), 50_000, 100_000)
+ expect(resultAt(out, 2)).toContain("removed to save context")
+ })
+
+ it("never stubs tools that cannot be re-run or small results", () => {
+ const edits = conversation(10, "file_edit")
+ expect(resultAt(new StaleToolResultPruner().apply(edits, 50_000, 100_000), 2)).toBe(BIG)
+ })
+
+ it("resets when the history shrinks (condensed)", () => {
+ const pruner = new StaleToolResultPruner()
+ pruner.apply(conversation(10), 50_000, 100_000)
+ const condensed = conversation(3)
+ expect(pruner.apply(condensed, 50_000, 100_000)).toBe(condensed)
+ })
+})
diff --git a/src/core/sliding-window/staleToolResults.ts b/src/core/sliding-window/staleToolResults.ts
new file mode 100644
index 0000000000..451cb840da
--- /dev/null
+++ b/src/core/sliding-window/staleToolResults.ts
@@ -0,0 +1,96 @@
+import type { Anthropic } from "@anthropic-ai/sdk"
+
+import { toModelToolName } from "../../shared/toolAliases"
+
+/** Start stubbing stale tool results once context passes this fraction of the window. */
+const PRUNE_TRIGGER_FRACTION = 0.4
+/** The most recent tool results are always sent verbatim. */
+const KEEP_RECENT_TOOL_RESULTS = 4
+/** The prune boundary only advances in batches this large, so the request prefix
+ * (and the provider's prompt cache) stays stable between prunes. */
+const PRUNE_BATCH = 6
+/** Results shorter than this are not worth stubbing. */
+const PRUNE_MIN_CHARS = 1500
+/** Tools whose output is bulky and can simply be re-fetched. */
+const PRUNABLE_TOOLS = new Set(["read_file", "execute_command", "codebase_search", "web_fetch", "web_search"])
+
+type Message = Anthropic.Messages.MessageParam
+type Block = Anthropic.Messages.ContentBlockParam
+
+function resultText(block: Anthropic.Messages.ToolResultBlockParam): string | undefined {
+ if (typeof block.content === "string") return block.content
+ if (!block.content) return ""
+ // Leave results with images alone: they cannot be re-derived from the stub.
+ if (block.content.some((part) => part.type !== "text")) return undefined
+ return block.content.map((part) => (part.type === "text" ? part.text : "")).join("\n")
+}
+
+/**
+ * Once context is large, stop resending old bulky tool results verbatim. Only the
+ * outgoing request is stubbed; the stored conversation is never touched. The
+ * boundary only advances in batches so the request prefix stays identical between
+ * advances and the provider's prompt cache keeps hitting.
+ */
+export class StaleToolResultPruner {
+ /** Tool results in messages at indexes below this are sent as short stubs. */
+ private prunedBefore = 0
+ private lastLength = 0
+
+ reset(): void {
+ this.prunedBefore = 0
+ this.lastLength = 0
+ }
+
+ apply(messages: T[], contextTokens: number, contextWindow: number): T[] {
+ // A shorter history means it was condensed or truncated: indexes shifted.
+ if (messages.length < this.lastLength) this.prunedBefore = 0
+ this.lastLength = messages.length
+
+ this.advanceBoundary(messages, contextTokens, contextWindow)
+ if (this.prunedBefore === 0) return messages
+
+ const toolNames = new Map()
+ for (const message of messages) {
+ if (message.role !== "assistant" || typeof message.content === "string") continue
+ for (const block of message.content) {
+ if (block.type === "tool_use") toolNames.set(block.id, block.name)
+ }
+ }
+
+ return messages.map((message, index) => {
+ if (index >= this.prunedBefore || message.role !== "user" || typeof message.content === "string") {
+ return message
+ }
+ let changed = false
+ const content = message.content.map((block): Block => {
+ if (block.type !== "tool_result") return block
+ const name = toolNames.get(block.tool_use_id) ?? ""
+ const text = resultText(block)
+ if (!PRUNABLE_TOOLS.has(name) || text === undefined || text.length < PRUNE_MIN_CHARS) return block
+ changed = true
+ const lines = text.split("\n").length
+ return {
+ ...block,
+ content: `[Earlier ${toModelToolName(name)} result (${lines} lines) removed to save context. Re-run the call if you still need it.]`,
+ }
+ })
+ return changed ? { ...message, content } : message
+ })
+ }
+
+ private advanceBoundary(messages: Message[], contextTokens: number, contextWindow: number): void {
+ if (!contextWindow || contextTokens < contextWindow * PRUNE_TRIGGER_FRACTION) return
+ // One entry per tool_result block, holding the index of its message.
+ const resultMessageIndexes: number[] = []
+ messages.forEach((message, index) => {
+ if (message.role !== "user" || typeof message.content === "string") return
+ for (const block of message.content) {
+ if (block.type === "tool_result") resultMessageIndexes.push(index)
+ }
+ })
+ if (resultMessageIndexes.length <= KEEP_RECENT_TOOL_RESULTS) return
+ const boundary = resultMessageIndexes[resultMessageIndexes.length - KEEP_RECENT_TOOL_RESULTS]
+ const newlyStale = resultMessageIndexes.filter((index) => index >= this.prunedBefore && index < boundary).length
+ if (newlyStale >= PRUNE_BATCH) this.prunedBefore = boundary
+ }
+}
diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts
index 948d6497fb..d40df21040 100644
--- a/src/core/task/Task.ts
+++ b/src/core/task/Task.ts
@@ -111,6 +111,7 @@ import {
toolUseIdsRequiringResults,
} from "./toolCallResultPairing" // forked_change: keep assistant tool_calls and tool_results paired 1:1
import { truncateConversationIfNeeded } from "../sliding-window"
+import { StaleToolResultPruner } from "../sliding-window/staleToolResults"
import { ClineProvider } from "../webview/ClineProvider"
import { MultiSearchReplaceDiffStrategy } from "../diff/strategies/multi-search-replace"
import { MultiFileSearchReplaceDiffStrategy } from "../diff/strategies/multi-file-search-replace"
@@ -370,6 +371,11 @@ export class Task extends EventEmitter implements TaskLike {
// executeCommandTool from the model's `isDangerous` param. Read by the command
// branch of askApproval so the "Approve for me" mode auto-approves only safe commands.
pendingCommandIsDangerous: boolean = false
+ // True when the pending command only observes the workspace (rg, ls, git diff, ...) and
+ // so skips the approval prompt in every approval mode. See core/tools/readOnlyCommand.ts.
+ pendingCommandIsReadOnly: boolean = false
+ // Stubs old bulky tool results in the outgoing request once context is large.
+ private readonly staleToolResultPruner = new StaleToolResultPruner()
// TaskStatus
idleAsk?: ClineMessage
@@ -4229,6 +4235,12 @@ export class Task extends EventEmitter implements TaskLike {
// kilocode_change: preserve reasoning
...("reasoning" in msg ? { reasoning: (msg as any).reasoning } : {}),
}))
+ // Only the outgoing copy is pruned; apiConversationHistory keeps every result.
+ cleanConversationHistory = this.staleToolResultPruner.apply(
+ cleanConversationHistory,
+ this.getTokenUsage().contextTokens ?? 0,
+ this.api.getModel().info.contextWindow,
+ )
// forked_change start
// Fetch project properties for KiloCode provider tracking
diff --git a/src/core/tools/__tests__/readFileTool.spec.ts b/src/core/tools/__tests__/readFileTool.spec.ts
index ab844a5a6e..af1bef10bd 100644
--- a/src/core/tools/__tests__/readFileTool.spec.ts
+++ b/src/core/tools/__tests__/readFileTool.spec.ts
@@ -546,7 +546,7 @@ describe("read_file tool with maxReadFileLine setting", () => {
expect(result).toContain("No file content was returned")
expect(result).toContain("continue the analysis or make the edit")
expect(result).toContain("Do not walk through nearby offsets")
- expect(result).toContain("use search_files for the relevant symbol or text")
+ expect(result).toContain("use rg -n via the Bash tool for the relevant symbol or text")
expect(result).toContain("Do not stop or ask the user")
expect(mockedExtractTextFromFile).not.toHaveBeenCalled()
expect(mockCline.ask).not.toHaveBeenCalledWith("mistake_limit_reached", expect.anything())
diff --git a/src/core/tools/__tests__/readOnlyCommand.spec.ts b/src/core/tools/__tests__/readOnlyCommand.spec.ts
new file mode 100644
index 0000000000..be9b001002
--- /dev/null
+++ b/src/core/tools/__tests__/readOnlyCommand.spec.ts
@@ -0,0 +1,47 @@
+// npx vitest run src/core/tools/__tests__/readOnlyCommand.spec.ts
+
+import { describe, expect, it } from "vitest"
+
+import { isReadOnlyCommand } from "../readOnlyCommand"
+
+describe("isReadOnlyCommand", () => {
+ it.each([
+ `rg -n "foo" src/`,
+ `rg -n "=>" src -g '*.ts'`,
+ `rg --files src | head -50`,
+ `grep -rn "a|b" . --include='*.ts' 2>/dev/null`,
+ `find . -name '*.ts' -not -path '*/node_modules/*'`,
+ `ls -la src/ && pwd`,
+ `cd src && rg -l TODO | wc -l`,
+ `git status --short`,
+ `git diff --stat; git log --oneline -20`,
+ `cat package.json | jq .version`,
+ ])("treats %s as read-only", (command) => {
+ expect(isReadOnlyCommand(command)).toBe(true)
+ })
+
+ it.each([
+ ``,
+ `rm -rf node_modules`,
+ `echo hi > file.txt`,
+ `cat a >> b`,
+ `rg foo | xargs rm`,
+ `find . -name '*.log' -delete`,
+ `find . -exec rm {} \;`,
+ `rg --pre ./evil.sh foo`,
+ `sort -o out.txt in.txt`,
+ `ls $(rm -rf /)`,
+ "ls `whoami`",
+ `git commit -m x`,
+ `git -c core.pager=evil log`,
+ `git diff --output=out.patch`,
+ `ls; rm file`,
+ `ls && npm install`,
+ `sed -i s/a/b/ file`,
+ `FOO=1 rg x`,
+ `cat < {
+ expect(isReadOnlyCommand(command)).toBe(false)
+ })
+})
diff --git a/src/core/tools/attemptCompletionTool.ts b/src/core/tools/attemptCompletionTool.ts
index b9188de46d..2e20ff8673 100644
--- a/src/core/tools/attemptCompletionTool.ts
+++ b/src/core/tools/attemptCompletionTool.ts
@@ -152,7 +152,7 @@ export async function attemptCompletionTool(
cline.consecutiveMistakeCount = 0
// Command execution is permanently disabled in attempt_completion
- // Users must use execute_command tool separately before attempt_completion
+ // Users must use the Bash tool separately before attempt_completion
await cline.say(
"completion_result",
result,
diff --git a/src/core/tools/executeCommandTool.ts b/src/core/tools/executeCommandTool.ts
index c9602fddda..4b4e75e937 100644
--- a/src/core/tools/executeCommandTool.ts
+++ b/src/core/tools/executeCommandTool.ts
@@ -13,6 +13,7 @@ import { Task } from "../task/Task"
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag, ToolResponse } from "../../shared/tools"
import { formatResponse } from "../prompts/responses"
import { unescapeHtmlEntities } from "../../utils/text-normalization"
+import { isReadOnlyCommand } from "./readOnlyCommand"
import { ExitCodeDetails, RooTerminalCallbacks, RooTerminalProcess } from "../../integrations/terminal/types"
import { TerminalRegistry } from "../../integrations/terminal/TerminalRegistry"
import { Terminal } from "../../integrations/terminal/Terminal"
@@ -68,6 +69,7 @@ export async function executeCommandTool(
// honour the user's command approval mode ("Approve for me" auto-approves only
// non-dangerous commands).
task.pendingCommandIsDangerous = isDangerousCommand
+ task.pendingCommandIsReadOnly = !isDangerousCommand && isReadOnlyCommand(command)
const didApprove = await askApproval("command", askText)
if (!didApprove) {
diff --git a/src/core/tools/fileEditTool.ts b/src/core/tools/fileEditTool.ts
index b5c9c804ee..4f909fc2fa 100644
--- a/src/core/tools/fileEditTool.ts
+++ b/src/core/tools/fileEditTool.ts
@@ -395,14 +395,48 @@ export function performReplacement(
// Not found by any strategy.
const preview = oldString.length > 100 ? oldString.slice(0, 100) + "..." : oldString
const contentPreview = content.length > 200 ? content.slice(0, 200) + "..." : content
+ const closest = closestRegion(content, oldString)
throw new Error(
`old_string not found in file content.\n` +
`Searched for (${oldString.length} chars): ${JSON.stringify(preview)}\n` +
- `File starts with: ${JSON.stringify(contentPreview)}\n` +
+ (closest ? `${closest}\n` : `File starts with: ${JSON.stringify(contentPreview)}\n`) +
"No edit was applied. DO NOT guess or invent a corrected old_string. Re-read the intended target and copy the exact current text before retrying.",
)
}
+/**
+ * Up to 7 numbered lines around the file line that best resembles `oldString`,
+ * with exact whitespace, so the model can retry without another read.
+ */
+function closestRegion(content: string, oldString: string): string | undefined {
+ const tokens = (text: string) => new Set(text.toLowerCase().match(/[a-z0-9_$]+/g) ?? [])
+ const probe = oldString.split("\n").find((line) => line.trim().length >= 4)
+ if (!probe) return undefined
+ const wanted = tokens(probe)
+ if (wanted.size === 0) return undefined
+ const lines = content.split("\n")
+ let bestIndex = -1
+ let bestScore = 0
+ for (let i = 0; i < lines.length; i++) {
+ const have = tokens(lines[i])
+ let shared = 0
+ for (const token of wanted) if (have.has(token)) shared++
+ const score = shared / (wanted.size + have.size - shared || 1)
+ if (score > bestScore) {
+ bestScore = score
+ bestIndex = i
+ }
+ }
+ if (bestIndex < 0 || bestScore < 0.5) return undefined
+ const from = Math.max(0, bestIndex - 3)
+ const to = Math.min(lines.length, bestIndex + 4)
+ const shown = lines
+ .slice(from, to)
+ .map((line, i) => `${String(from + i + 1).padStart(6, " ")}|${line.replace(/\r$/, "")}`)
+ .join("\n")
+ return `Closest match in the file (lines ${from + 1}-${to}, exact whitespace shown):\n${shown}`
+}
+
function countOccurrences(haystack: string, needle: string): number {
if (!needle) {
return 0
diff --git a/src/core/tools/readFileTool.ts b/src/core/tools/readFileTool.ts
index 22be407c43..5e47186ae6 100644
--- a/src/core/tools/readFileTool.ts
+++ b/src/core/tools/readFileTool.ts
@@ -476,7 +476,7 @@ Do not call read_file again with the same path, offset, and limit. Choose the ne
- If the earlier content is sufficient, continue the analysis or make the edit.
- ${nextRegionHint}
- Do not walk through nearby offsets on this file one-by-one; that is still a repeated-read loop.
-- If you do not know the target line, use search_files for the relevant symbol or text, then read only the matched range.
+- If you do not know the target line, use rg -n via the Bash tool for the relevant symbol or text, then read only the matched range.
Do not stop or ask the user because of this skipped read; proceed with the best next action above.`,
})
diff --git a/src/core/tools/readOnlyCommand.ts b/src/core/tools/readOnlyCommand.ts
new file mode 100644
index 0000000000..432b34c135
--- /dev/null
+++ b/src/core/tools/readOnlyCommand.ts
@@ -0,0 +1,154 @@
+/**
+ * Conservative detector for shell commands that only observe the workspace
+ * (rg, grep, find, ls, cat, git status, ...). Such commands skip the approval
+ * prompt in every command approval mode, which is what lets the Bash tool stand
+ * in for dedicated search/list tools. A false negative just means a prompt; a false
+ * positive would run something unreviewed, so anything unrecognised is rejected.
+ */
+
+const READ_ONLY_COMMANDS = new Set([
+ "rg",
+ "grep",
+ "egrep",
+ "fgrep",
+ "find",
+ "fd",
+ "ls",
+ "tree",
+ "cat",
+ "head",
+ "tail",
+ "wc",
+ "file",
+ "stat",
+ "pwd",
+ "echo",
+ "sort",
+ "uniq",
+ "cut",
+ "tr",
+ "nl",
+ "du",
+ "df",
+ "which",
+ "basename",
+ "dirname",
+ "realpath",
+ "diff",
+ "jq",
+ "column",
+ "cd",
+ "true",
+ "git",
+])
+
+const READ_ONLY_GIT = new Set([
+ "status",
+ "diff",
+ "log",
+ "show",
+ "blame",
+ "ls-files",
+ "ls-tree",
+ "grep",
+ "rev-parse",
+ "rev-list",
+ "describe",
+ "shortlog",
+ "cat-file",
+ "diff-tree",
+ "merge-base",
+ "name-rev",
+ "check-ignore",
+])
+
+/** Flags that make an otherwise read-only command run code or write files. */
+const UNSAFE_FLAGS: Record = {
+ find: /^-(exec|execdir|ok|okdir|delete|fprint|fprint0|fprintf|fls)$/,
+ fd: /^(-x|-X|--exec|--exec-batch)$/,
+ rg: /^(--pre|--pre-glob|--hostname-bin)(=|$)/,
+ sort: /^(-o|--output)(=|$)/,
+ tree: /^-o$/,
+ git: /^(--output|--ext-diff|--textconv|-O|--open-files-in-pager)(=|$)/,
+}
+
+/** Split on unquoted shell operators; null if the command uses anything that could hide a write or a nested command. */
+function splitSegments(command: string): string[] | null {
+ const segments: string[] = []
+ let current = ""
+ let quote: "'" | '"' | null = null
+ for (let i = 0; i < command.length; i++) {
+ const ch = command[i]
+ if (quote === "'") {
+ if (ch === "'") quote = null
+ current += ch
+ continue
+ }
+ if (ch === "\\") {
+ current += ch + (command[i + 1] ?? "")
+ i++
+ continue
+ }
+ if (ch === "`" || (ch === "$" && command[i + 1] === "(")) return null
+ if (quote === '"') {
+ if (ch === '"') quote = null
+ current += ch
+ continue
+ }
+ if (ch === "'" || ch === '"') {
+ quote = ch
+ current += ch
+ continue
+ }
+ if (ch === "\n" || ch === "<" || ch === "(" || ch === ")" || ch === "{" || ch === "}") return null
+ if (ch === ">") return null
+ if (ch === "|" || ch === ";" || ch === "&") {
+ // `||`, `&&`, `|&`: swallow the doubled operator.
+ if (command[i + 1] === ch || (ch === "|" && command[i + 1] === "&")) i++
+ segments.push(current)
+ current = ""
+ continue
+ }
+ current += ch
+ }
+ if (quote) return null
+ segments.push(current)
+ return segments
+}
+
+/** Words of a single segment with quotes removed (enough to inspect the command name and flags). */
+function words(segment: string): string[] {
+ const out: string[] = []
+ for (const match of segment.matchAll(/"((?:[^"\\]|\\.)*)"|'([^']*)'|((?:\\.|[^\s"'\\])+)/g)) {
+ out.push(match[1] ?? match[2] ?? match[3] ?? "")
+ }
+ return out
+}
+
+export function isReadOnlyCommand(command: string): boolean {
+ // Harmless redirections the model adds constantly; removed before looking for real ones.
+ const cleaned = command
+ .replace(/\s\d?>\s*\/dev\/null/g, " ")
+ .replace(/\s2>&1/g, " ")
+ .trim()
+ if (!cleaned) return false
+ const segments = splitSegments(cleaned)
+ if (!segments) return false
+ let sawCommand = false
+ for (const segment of segments) {
+ const w = words(segment)
+ if (w.length === 0) continue
+ const [name, ...rest] = w
+ if (!READ_ONLY_COMMANDS.has(name)) return false
+ sawCommand = true
+ if (name === "git") {
+ const sub = rest.find((arg) => !arg.startsWith("-"))
+ if (!sub || !READ_ONLY_GIT.has(sub)) return false
+ // `git -c core.pager=...` / `--exec-path` global options can run code.
+ if (rest.some((arg) => arg === "-c" || arg.startsWith("--exec-path"))) return false
+ }
+ const unsafe = UNSAFE_FLAGS[name]
+ if (unsafe && rest.some((arg) => unsafe.test(arg))) return false
+ }
+ return sawCommand
+}
diff --git a/src/integrations/terminal/ExecaTerminalProcess.ts b/src/integrations/terminal/ExecaTerminalProcess.ts
index 47bbf340ed..495aa416ac 100644
--- a/src/integrations/terminal/ExecaTerminalProcess.ts
+++ b/src/integrations/terminal/ExecaTerminalProcess.ts
@@ -8,6 +8,7 @@ import { readFileSync, unlinkSync } from "fs"
import type { RooTerminal } from "./types"
import { BaseTerminalProcess } from "./BaseTerminalProcess"
import { getShellEnvironment, getCapturedShell } from "./ShellEnvironment"
+import { getCommandShell } from "../../utils/shell"
export class ExecaTerminalProcess extends BaseTerminalProcess {
private terminalRef: WeakRef
@@ -48,7 +49,10 @@ export class ExecaTerminalProcess extends BaseTerminalProcess {
// On Windows, process.env already carries the full system PATH;
// using shell:true (cmd.exe) is the safest default there.
const isWindows = process.platform === "win32"
- const shellPath = isWindows ? true : getCapturedShell()
+ // The model writes bash syntax, so prefer bash (Git Bash on Windows) over the
+ // configured terminal profile; fall back to the profile / cmd.exe when absent.
+ const commandShell = getCommandShell()
+ const shellPath = commandShell.path ?? (isWindows ? true : getCapturedShell())
// Use the captured login-shell environment so that CLI tools
// installed via Homebrew, nvm, cargo, etc. are on PATH even when
diff --git a/src/package.json b/src/package.json
index 5843ba27ed..93c44e5b77 100644
--- a/src/package.json
+++ b/src/package.json
@@ -3,7 +3,7 @@
"displayName": "%extension.displayName%",
"description": "%extension.description%",
"publisher": "matterai",
- "version": "6.8.6",
+ "version": "6.9.0",
"icon": "assets/icons/matterai-ic.png",
"galleryBanner": {
"color": "#FFFFFF",
diff --git a/src/shared/toolAliases.ts b/src/shared/toolAliases.ts
new file mode 100644
index 0000000000..df9cbc7ab9
--- /dev/null
+++ b/src/shared/toolAliases.ts
@@ -0,0 +1,17 @@
+/**
+ * The model sees the shell tool as `Bash` (what most models are trained on),
+ * while the extension keeps `execute_command` as its internal tool name for
+ * approval, UI, mode groups and persisted history. Translate at the boundary.
+ */
+const MODEL_TO_INTERNAL: Record = { Bash: "execute_command" }
+const INTERNAL_TO_MODEL: Record = { execute_command: "Bash" }
+
+/** Name the model used in a tool call -> internal tool name. */
+export function toInternalToolName(name: string): string {
+ return MODEL_TO_INTERNAL[name] ?? name
+}
+
+/** Internal tool name -> name shown to the model. */
+export function toModelToolName(name: string): string {
+ return INTERNAL_TO_MODEL[name] ?? name
+}
diff --git a/src/shared/tools.ts b/src/shared/tools.ts
index 8d254ed115..05ac5a5bcf 100644
--- a/src/shared/tools.ts
+++ b/src/shared/tools.ts
@@ -279,8 +279,6 @@ export const TOOL_GROUPS: Record = {
tools: [
"read_file",
"fetch_instructions",
- "search_files",
- "list_files",
"list_code_definition_names",
"lsp",
"codebase_search",
diff --git a/src/utils/shell.ts b/src/utils/shell.ts
index 45253c31b0..8710c41df9 100644
--- a/src/utils/shell.ts
+++ b/src/utils/shell.ts
@@ -1,5 +1,6 @@
import * as vscode from "vscode"
import { userInfo } from "os"
+import * as fs from "fs"
import * as path from "path"
// Security: Allowlist of approved shell executables to prevent arbitrary command execution
@@ -368,3 +369,53 @@ export function getShell(): string {
return shell
}
+
+// -----------------------------------------------------
+// 6) Shell used by the Bash tool
+// -----------------------------------------------------
+
+export interface CommandShell {
+ /** Shell executable to spawn, or undefined to use the platform default (cmd.exe on Windows). */
+ path: string | undefined
+ /** True when the shell understands bash syntax (rg ... | head, &&, $(...), ...). */
+ isBash: boolean
+}
+
+function firstExistingFile(candidates: (string | undefined)[]): string | undefined {
+ return candidates.find((candidate): candidate is string => {
+ if (!candidate) return false
+ try {
+ return fs.statSync(candidate).isFile()
+ } catch {
+ return false
+ }
+ })
+}
+
+let cachedCommandShell: CommandShell | undefined
+
+/**
+ * The model writes bash syntax, so commands run in bash instead of whatever the
+ * VS Code terminal profile is (fish and csh choke on `&&`, `$?` and friends):
+ * bash on macOS/Linux, Git Bash on Windows. When bash is missing, fall back to
+ * the configured shell (POSIX) or cmd.exe (Windows) and report isBash=false on
+ * Windows so the system prompt can warn the model.
+ */
+export function getCommandShell(): CommandShell {
+ if (cachedCommandShell) return cachedCommandShell
+ if (process.platform === "win32") {
+ const roots = [process.env.ProgramFiles, process.env["ProgramFiles(x86)"]]
+ const gitBash = firstExistingFile(
+ roots.flatMap((root) =>
+ root
+ ? [path.join(root, "Git", "bin", "bash.exe"), path.join(root, "Git", "usr", "bin", "bash.exe")]
+ : [],
+ ),
+ )
+ cachedCommandShell = { path: gitBash, isBash: gitBash !== undefined }
+ } else {
+ const bash = firstExistingFile(["/bin/bash", "/usr/bin/bash", "/usr/local/bin/bash", "/opt/homebrew/bin/bash"])
+ cachedCommandShell = bash ? { path: bash, isBash: true } : { path: undefined, isBash: false }
+ }
+ return cachedCommandShell
+}