Skip to main content
InteractiveBox attaches your terminal directly to a shell running inside a VM — like SSH into a sandbox. Use it for interactive tools, REPLs, debugging sessions, or any workflow where you need a live terminal.

What you’ll build

A script that:
  1. Launches an InteractiveBox with a shell
  2. Runs interactive commands in a TTY session
  3. Connects to a Python REPL inside the VM

Prerequisites

pip install boxlite
Requires Python 3.10+.

Step 1: Start a shell session

Launch an InteractiveBox and drop into a shell. The session stays open until you type exit or the shell terminates.
shell.py
import asyncio
from boxlite import InteractiveBox


async def main():
    async with InteractiveBox(image="alpine:latest") as box:
        # You're now in an interactive shell inside the VM
        # Type commands, see output in real-time
        # Type "exit" to close the session
        await box.wait()

    print("Shell session ended")


if __name__ == "__main__":
    asyncio.run(main())
python shell.py
# You'll see an Alpine Linux shell prompt
# Try: ls, whoami, cat /etc/os-release
# Type "exit" to quit
What’s happening:
  • InteractiveBox creates a VM with Alpine Linux and attaches your terminal to /bin/sh
  • Your keystrokes go directly into the VM’s shell, and output streams back in real-time
  • wait() blocks until the shell process exits (when you type exit or press Ctrl+D)

Step 2: Choose your shell

You can run any shell or REPL available in the image. Specify it with the shell parameter.
bash_session.py
import asyncio
from boxlite import InteractiveBox


async def main():
    # Use bash (available in Ubuntu, not Alpine)
    async with InteractiveBox(
        image="ubuntu:22.04",
        shell="/bin/bash"
    ) as box:
        await box.wait()


if __name__ == "__main__":
    asyncio.run(main())
python_repl.py
import asyncio
from boxlite import InteractiveBox


async def main():
    # Drop straight into a Python REPL
    async with InteractiveBox(
        image="python:slim",
        shell="/usr/bin/python3"
    ) as box:
        await box.wait()


if __name__ == "__main__":
    asyncio.run(main())
Make sure the shell you specify actually exists in the image. Alpine uses /bin/sh (busybox), not /bin/bash. Ubuntu has both.

Step 3: Choose the right TTY mode

The tty parameter controls how InteractiveBox handles terminal I/O. The right choice depends on how you’re using the box.
ValuePythonNode.jsBehaviorUse when…
Auto-detecttty=None (default)tty: undefined (default)Checks sys.stdin.isatty() / process.stdin.isTTYYou’re not sure — this works in most cases
Force TTYtty=Truetty: trueAlways enables PTY with I/O forwardingYou’re running from a terminal and want interactive control
No I/Otty=Falsetty: falseDisables I/O forwarding entirelyYou’re controlling the box programmatically with exec()
tty_modes.py
import asyncio
from boxlite import InteractiveBox


async def main():
    # Force TTY mode — always interactive
    async with InteractiveBox(
        image="alpine:latest",
        tty=True
    ) as box:
        await box.wait()


if __name__ == "__main__":
    asyncio.run(main())
programmatic.py
import asyncio
from boxlite import InteractiveBox


async def main():
    # No I/O forwarding — use exec() to send commands
    async with InteractiveBox(
        image="alpine:latest",
        tty=False
    ) as box:
        # InteractiveBox extends SimpleBox, so exec() works
        result = await box.exec("cat", "/etc/os-release")
        print(result.stdout)


if __name__ == "__main__":
    asyncio.run(main())
InteractiveBox extends SimpleBox, so you always have access to exec() for running one-off commands. The tty parameter only controls whether the shell session itself gets I/O forwarding — exec() works regardless.

What’s next?

Run any language or tool

Use SimpleBox with custom images to run Node.js, Go, Rust, or any CLI tool.

Handle errors and debug

Catch exceptions, handle timeouts, and debug failures.

InteractiveBox API reference

Full API docs for InteractiveBox constructor options and methods.