> ## Documentation Index
> Fetch the complete documentation index at: https://docs.runloop.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Execute Commands on a Devbox

> Run and execute code at scale

export const ExampleRepoLink = props => {
  return <Info><h3><a href={props.link}>Full example on GitHub</a></h3></Info>;
};

<Tip>Start with the [Runloop Quickstart](/docs/tutorials/quickstart) to use the examples below.</Tip>

## Execute Commands

Once your Devbox is in a ready state you can execute commands to interact with it. The primary method of executing commands is the `exec` command.

<CodeGroup>
  ```python Python theme={null}
  result = await devbox.cmd.exec("echo Hello World")
  print(f"Command output: {await result.stdout()}")
  print(f"Exit code: {result.exit_code}")
  ```

  ```typescript TypeScript theme={null}
  const result = await devbox.cmd.exec("echo Hello World");
  console.log(`Command output: ${await result.stdout()}`);
  console.log(`Exit code: ${result.exitCode}`);
  ```
</CodeGroup>

### Long Running Commands

You can use `exec_async` to return a command object that you can use to control command execution.
This allows you to manage commands by running them in the background and control their lifecycle.

<Note>
  This function will return once the devbox has started the command execution. You can use the `command` object to control the command execution.
</Note>

<CodeGroup>
  ```python Python theme={null}
  command = await devbox.cmd.exec_async(
    "HOST=0.0.0.0; npx run http-server")
  # When you are done, you can stop the command
  await command.kill()
  ```

  ```typescript TypeScript theme={null}
  const command = await devbox.cmd.execAsync(
    "HOST=0.0.0.0; npx run http-server");
  // When you are done, you can stop the command
  await command.kill();
  ```
</CodeGroup>

### Streaming Output

You can stream stdout and stderr logs in real-time, this works for exec and execAsync.

<Note>
  Streaming is ideal for long-running commands where you want to see output as it's generated, such as builds, tests, or log tailing.
</Note>

<Steps title="Streaming Output">
  <Step title="Execute a command and stream output">
    <CodeGroup>
      {/* TODO: verify that indentation change is OK */}

      ```python Python theme={null}
      command = await devbox.cmd.exec_async(
        "HOST=0.0.0.0; npx run http-server",
        output=lambda x: print(x)
      )
      ```

      ```typescript Typescript theme={null}
      const command = await devbox.cmd.execAsync(
        "HOST=0.0.0.0; npx run http-server",
        { output: (x: string) => console.log(x) }
      );
      ```
    </CodeGroup>
  </Step>

  <Step title="Execute a command and stream STDOUT and STDERR">
    <CodeGroup>
      ```python Python theme={null}
      command = await devbox.cmd.exec_async(
        "HOST=0.0.0.0; npx run http-server",
        stdout=lambda x: print(x),
        stderr=lambda x: print(x)
      )
      ```

      ```typescript Typescript theme={null}
      const command = await devbox.cmd.execAsync(
        "HOST=0.0.0.0; npx run http-server",
        { stdout: (x: string) => console.log(x),
          stderr: (x: string) => console.error(x) }
      );
      ```
    </CodeGroup>
  </Step>
</Steps>

## Isolated Shells

By default, every Devbox command runs in a new shell session so the state of the shell is not preserved between commands.

<CodeGroup>
  ```python Python theme={null}
  await devbox.cmd.exec("export MY_VAR=123")

  ## New shell means MY_VAR is not defined
  exec_result = await devbox.cmd.exec("echo $MY_VAR")
  print(await exec_result.stdout())  # ""
  ```

  ```typescript TypeScript theme={null}
  await devbox.cmd.exec("export MY_VAR=123");

  // New shell means MY_VAR is not defined
  const execResult= await devbox.cmd.exec("echo $MY_VAR");
  console.log(await execResult.stdout());  // ""
  ```
</CodeGroup>

## Stateful Shells

You can use the `shell_name` parameter to use a 'stateful' shell. This means that the shell will maintain its state across commands including environment variables and working directory.

As an example, let's create a series of interdependent commands that need to be run in the same shell:

<Steps title="Using Stateful Shells">
  <Step title="Create and enter new directory">
    <CodeGroup>
      ```python Python theme={null}
      await devbox.cmd.exec(
        "mkdir test-area && cd test-area",
        shell_name="my-shell"
      )
      ```

      ```typescript TypeScript theme={null}
      await devbox.cmd.exec(
        "mkdir test-area && cd test-area",
        { shell_name: "my-shell" }
      )
      ```
    </CodeGroup>
  </Step>

  <Step title="Check new working directory is preserved">
    <CodeGroup>
      ```python Python theme={null}
      exec_result = await devbox.cmd.exec(
        "pwd", shell_name="my-shell")
      print(await exec_result.stdout())  # /home/user/test-area
      ```

      ```typescript TypeScript theme={null}
      const execResult = await devbox.cmd.exec(
        "pwd", { shell_name: "my-shell" });
      console.log(await execResult.stdout());  // /home/user/test-area
      ```
    </CodeGroup>
  </Step>

  <Step title="Environment variables are preserved">
    <CodeGroup>
      ```python Python theme={null}
      await devbox.cmd.exec(
        "export MY_VAR=123",
        shell_name="my-shell"
      )
      exec_result = await devbox.cmd.exec(
        "echo $MY_VAR",
        shell_name="my-shell"
      )
      print(await exec_result.stdout())  # 123
      ```

      ```typescript TypeScript theme={null}
      await devbox.cmd.exec(
        "export MY_VAR=123",
        { shell_name: "my-shell" }
      );
      const execResult = await devbox.cmd.exec(
        "echo $MY_VAR",
        { shell_name: "my-shell" }
      );
      console.log(await execResult.stdout());  // 123
      ```
    </CodeGroup>
  </Step>
</Steps>
