Documentation Index
Fetch the complete documentation index at: https://mintlify.com/QwenLM/qwen-code/llms.txt
Use this file to discover all available pages before exploring further.
Shell Tool (run_shell_command)
The shell tool allows Qwen Code to execute system commands, run scripts, and perform command-line operations.
Overview
Tool Name: run_shell_command
Display Name: Shell
Kind: Other
Description: Executes shell commands on the underlying system. Supports both foreground and background execution with optional interactive mode.
Parameters
interface ShellToolParams {
command: string; // Required: Command to execute
description?: string; // Optional: Command description
directory?: string; // Optional: Working directory
is_background: boolean; // Required: Background execution
timeout?: number; // Optional: Timeout in ms
}
Usage
Basic Command
run_shell_command({
command: 'ls -la',
is_background: false,
});
With Description
run_shell_command({
command: 'npm install',
description: 'Install project dependencies',
is_background: false,
});
In Specific Directory
run_shell_command({
command: './build.sh',
directory: 'scripts',
description: 'Run build script',
is_background: false,
});
Background Execution
run_shell_command({
command: 'npm run dev',
description: 'Start development server',
is_background: true,
});
With Timeout
run_shell_command({
command: 'npm test',
timeout: 60000, // 60 seconds
is_background: false,
});
Background vs Foreground
The is_background parameter is required and controls execution mode.
Foreground (is_background: false)
Use for:
- One-time commands:
ls, cat, grep
- Build commands:
npm run build, make
- Installation:
npm install, pip install
- Git operations:
git commit, git push
- Tests:
npm test, pytest
Behavior:
- Blocks until command completes
- Returns stdout, stderr, and exit code
- Default timeout: 120 seconds
- Can be customized with
timeout parameter
Background (is_background: true)
Use for:
- Development servers:
npm run dev, npm start
- Build watchers:
npm run watch, webpack --watch
- Database servers:
mongod, redis-server
- Web servers:
python -m http.server
- Any long-running process
Behavior:
- Returns immediately
- Process continues running
- Returns process ID (PID)
- No timeout applied
- Adds
[background] indicator to description
Command Execution Details
Shell Environment
Platform-specific shells:
- Windows:
cmd.exe /c
- Unix/Linux/macOS:
bash -c
Environment Variables:
QWEN_CODE=1 # Always set for spawned processes
Working Directory
By default, commands run in the project root directory.
Use the directory parameter for relative paths:
// Runs in <project-root>/scripts
run_shell_command({
command: './deploy.sh',
directory: 'scripts',
is_background: false,
});
Output Handling
The tool returns:
interface ShellResult {
command: string; // Executed command
directory?: string; // Working directory
stdout: string; // Standard output
stderr: string; // Standard error
exitCode?: number; // Exit code
signal?: string; // Signal if terminated
backgroundPids?: number[]; // PIDs if background
error?: string; // Error message
}
Interactive Commands
Enabling Interactive Shell
Set in settings.json:
{
"tools": {
"shell": {
"enableInteractiveShell": true,
"showColor": true,
"pager": "less"
}
}
}
Supported Interactive Commands
With enableInteractiveShell enabled:
- Text editors:
vim, nano, emacs
- Interactive tools:
htop, top
- Version control:
git rebase -i, git add -p
- Other TUIs: Any terminal-based UI
Usage
When an interactive command is running:
- Press
Ctrl+F to focus on the interactive shell
- Interact normally with the command
- Exit the command normally (e.g.,
:q for vim)
- Control returns to Qwen Code
Configuration
Shell Settings
{
"tools": {
"shell": {
"enableInteractiveShell": boolean, // Enable pty for interactive commands
"showColor": boolean, // Show ANSI colors (requires interactive)
"pager": string // Pager command (default: "cat")
}
}
}
Command Restrictions
Restrict or block specific commands:
Allow only specific commands:
{
"tools": {
"core": [
"run_shell_command(git)",
"run_shell_command(npm)",
"run_shell_command(node)"
]
}
}
Result:
git status ✅ Allowed
npm install ✅ Allowed
rm -rf / ❌ Blocked
Block specific commands:
{
"tools": {
"core": ["run_shell_command"], // Allow all
"exclude": [
"run_shell_command(rm)",
"run_shell_command(sudo)",
"run_shell_command(curl)"
]
}
}
Result:
git status ✅ Allowed
npm install ✅ Allowed
rm file.txt ❌ Blocked
sudo apt update ❌ Blocked
Blocklist Takes Precedence
If a command is in both lists, it’s blocked:
{
"tools": {
"core": ["run_shell_command(git)"],
"exclude": ["run_shell_command(git push)"]
}
}
Result:
git status ✅ Allowed
git push ❌ Blocked (more specific)
Command Chaining
Chained commands are validated separately:
# Each part is checked
"git add . && git commit -m 'msg' && git push"
# If any part is blocked, entire command is blocked
Note: Command restrictions use simple prefix matching and are not a security mechanism. They help prevent accidental dangerous operations but should not be relied upon for security.
User Confirmation
Commands requiring user confirmation:
Auto-Approved Commands
Safe, read-only operations:
ls, cat, echo
git status, git log, git diff
npm list
- Custom allowlisted commands
Requires Confirmation
Potentially dangerous operations:
- File modifications:
rm, mv, cp
- System commands:
sudo, chmod, chown
- Network:
curl, wget, ssh
- Installation:
npm install, pip install
- Custom blocklisted commands
Confirmation Dialog
When confirmation is required:
Confirm Shell Command
Command: rm -rf dist/
Root Command: rm
Options:
[P]roceed once
[A]lways allow this command
[N]ever allow this command
[C]ancel
Choosing “Always allow” adds the command to the allowlist for the session.
Security Considerations
Path Validation
Working directories are validated:
if (!workspaceContext.isPathWithinWorkspace(directory)) {
return 'Directory must be within workspace';
}
Command Injection
Be cautious with:
- User-provided command strings
- Interpolated variables
- Shell metacharacters:
;, &&, ||, |, >, <
Best Practices
-
Avoid user input in commands:
// ❌ Dangerous
`rm ${userInput}`
// ✅ Safe
'rm file.txt'
-
Use blocklist for dangerous commands:
{
"tools": {
"exclude": ["run_shell_command(rm)", "run_shell_command(sudo)"]
}
}
-
Enable sandboxing:
export QWEN_SANDBOX=docker
-
Review confirmation prompts:
- Don’t blindly approve commands
- Understand what each command does
- Use “Never allow” for suspicious commands
Implementation
Location: packages/core/src/tools/shell.ts
export class ShellTool extends BaseDeclarativeTool<
ShellToolParams,
ToolResult
> {
static readonly Name = ToolNames.RUN_SHELL_COMMAND;
private readonly allowlist = new Set<string>();
constructor(private readonly config: Config) {
super(
ShellTool.Name,
ToolDisplayNames.RUN_SHELL_COMMAND,
'Executes shell commands...',
Kind.Other,
{ /* schema */ },
);
}
protected override validateToolParamValues(
params: ShellToolParams,
): string | null {
// Validate command
if (!params.command || params.command.trim() === '') {
return 'Command must not be empty';
}
// Validate directory
if (params.directory) {
const resolvedDir = path.resolve(
this.config.getTargetDir(),
params.directory,
);
if (!workspaceContext.isPathWithinWorkspace(resolvedDir)) {
return 'Directory must be within workspace';
}
}
// Check command restrictions
const command = stripShellWrapper(params.command);
if (!isCommandAllowed(command, this.config)) {
return `Command not allowed: ${command}`;
}
return null;
}
}
Service
Location: packages/core/src/services/shellExecutionService.ts
Handles actual command execution:
export class ShellExecutionService {
async executeCommand(
command: string,
options: ShellExecutionConfig,
): Promise<ShellResult> {
const shell = process.platform === 'win32' ? 'cmd.exe' : 'bash';
const shellArgs = process.platform === 'win32' ? ['/c'] : ['-c'];
const child = spawn(shell, [...shellArgs, command], {
cwd: options.cwd,
env: { ...process.env, QWEN_CODE: '1' },
signal: options.signal,
});
// Handle stdout, stderr, exit code
// ...
}
}
Examples
Development Workflow
// Install dependencies
run_shell_command({
command: 'npm install',
description: 'Install dependencies',
is_background: false,
});
// Start dev server in background
run_shell_command({
command: 'npm run dev',
description: 'Start dev server',
is_background: true,
});
// Run tests
run_shell_command({
command: 'npm test',
description: 'Run test suite',
is_background: false,
});
Git Workflow
// Check status
run_shell_command({
command: 'git status',
is_background: false,
});
// Stage and commit
run_shell_command({
command: 'git add . && git commit -m "feat: add feature"',
description: 'Stage and commit changes',
is_background: false,
});
// Push to remote
run_shell_command({
command: 'git push origin main',
is_background: false,
});
Build and Deploy
// Build project
run_shell_command({
command: 'npm run build',
description: 'Build for production',
timeout: 300000, // 5 minutes
is_background: false,
});
// Run deployment script
run_shell_command({
command: './deploy.sh production',
directory: 'scripts',
description: 'Deploy to production',
is_background: false,
});
Troubleshooting
Command Not Found
Error: command not found: mycommand
Solutions:
- Check if command is in PATH
- Use absolute path:
/usr/local/bin/mycommand
- Check spelling and availability
Permission Denied
Error: Permission denied
Solutions:
- Check file permissions:
chmod +x script.sh
- Run from correct directory
- Don’t use
sudo (blocked by default)
Timeout
Error: Command timed out
Solutions:
- Increase timeout:
timeout: 300000
- Use background execution:
is_background: true
- Optimize slow command
Interactive Command Fails
Error: Input/output error
Solution:
Enable interactive shell:
{
"tools": {
"shell": {
"enableInteractiveShell": true
}
}
}
Next Steps