> ## 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

> Execute shell commands with the run_shell_command tool

# 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

```typescript theme={null}
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

```typescript theme={null}
run_shell_command({
  command: 'ls -la',
  is_background: false,
});
```

### With Description

```typescript theme={null}
run_shell_command({
  command: 'npm install',
  description: 'Install project dependencies',
  is_background: false,
});
```

### In Specific Directory

```typescript theme={null}
run_shell_command({
  command: './build.sh',
  directory: 'scripts',
  description: 'Run build script',
  is_background: false,
});
```

### Background Execution

```typescript theme={null}
run_shell_command({
  command: 'npm run dev',
  description: 'Start development server',
  is_background: true,
});
```

### With Timeout

```typescript theme={null}
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:**

```bash theme={null}
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:

```typescript theme={null}
// Runs in <project-root>/scripts
run_shell_command({
  command: './deploy.sh',
  directory: 'scripts',
  is_background: false,
});
```

### Output Handling

The tool returns:

```typescript theme={null}
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`:

```json theme={null}
{
  "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:

1. Press `Ctrl+F` to focus on the interactive shell
2. Interact normally with the command
3. Exit the command normally (e.g., `:q` for vim)
4. Control returns to Qwen Code

## Configuration

### Shell Settings

```json theme={null}
{
  "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:

#### Allowlist (Core Tools)

Allow only specific commands:

```json theme={null}
{
  "tools": {
    "core": [
      "run_shell_command(git)",
      "run_shell_command(npm)",
      "run_shell_command(node)"
    ]
  }
}
```

**Result:**

* `git status` ✅ Allowed
* `npm install` ✅ Allowed
* `rm -rf /` ❌ Blocked

#### Blocklist (Exclude Tools)

Block specific commands:

```json theme={null}
{
  "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:

```json theme={null}
{
  "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:

```bash theme={null}
# 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:

```typescript theme={null}
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

1. **Avoid user input in commands:**
   ```typescript theme={null}
   // ❌ Dangerous
   `rm ${userInput}`

   // ✅ Safe
   'rm file.txt'
   ```

2. **Use blocklist for dangerous commands:**
   ```json theme={null}
   {
     "tools": {
       "exclude": ["run_shell_command(rm)", "run_shell_command(sudo)"]
     }
   }
   ```

3. **Enable sandboxing:**
   ```bash theme={null}
   export QWEN_SANDBOX=docker
   ```

4. **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`

### Tool Class

```typescript theme={null}
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:

```typescript theme={null}
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

```typescript theme={null}
// 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

```typescript theme={null}
// 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

```typescript theme={null}
// 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:**

1. Check if command is in PATH
2. Use absolute path: `/usr/local/bin/mycommand`
3. Check spelling and availability

### Permission Denied

**Error:** `Permission denied`

**Solutions:**

1. Check file permissions: `chmod +x script.sh`
2. Run from correct directory
3. Don't use `sudo` (blocked by default)

### Timeout

**Error:** `Command timed out`

**Solutions:**

1. Increase timeout: `timeout: 300000`
2. Use background execution: `is_background: true`
3. Optimize slow command

### Interactive Command Fails

**Error:** `Input/output error`

**Solution:**
Enable interactive shell:

```json theme={null}
{
  "tools": {
    "shell": {
      "enableInteractiveShell": true
    }
  }
}
```

## Next Steps

* [Task Tool](./task.mdx) - Delegate complex tasks
* [File System Tools](./file-system.mdx) - File operations
* [Tools System](../tools-system.mdx) - Tools architecture
* [Sandbox Tool](./sandbox.mdx) - Sandboxed execution
