Skip to content

Repository files navigation

CLI Sandbox Environment

This project provides a containerized and isolated development environment for any folder on your system, using Docker and a bash script as an orchestrator.

The cuybox.sh script handles building the necessary Docker image, as well as creating, managing, and connecting to persistent containers, ensuring that each working directory has its own unique and reusable sandbox.

Features

  • Isolated Environments: Each sandbox is linked to an absolute directory path, mounting its content into /sandbox inside the container.
  • Intelligent Persistence: Containers are not deleted upon exit. The script automatically reconnects to a container if it's already running or starts it if it's stopped.
  • Unique & Predictable Naming: Each container's name is generated from a tag (the folder's name or a custom one), a 4-character hash of the path, and an index to resolve collisions ({tag}-{hash}-{index}).
  • Path Tracking: A config file ($XDG_CONFIG_HOME/cuybox/state.json, defaulting to ~/.config/cuybox/state.json) keeps a record of paths and their sandboxes to prevent collisions and manage indices.
  • Pre-configured Environment: The Docker image comes with nvm and the latest version of Node.js v22 ready to use.
  • Quiet OpenCode Defaults: OpenCode ignores common dependency trees, build outputs, caches, logs, binaries, and lockfiles from many language ecosystems when watching for filesystem changes.
  • Optional Tool Catalog: Discover and explicitly install optional tools inside a sandbox with cuybox-install; optional tools are not baked into every container.
  • Graceful Lifecycle: Containers run under tini with an idle process so they stop quickly and cleanly even after long sessions.
  • Custom Attach Program: Sandboxes attach with byobu by default, with --program available for alternatives such as bash.
  • Flexibility: Allows passing custom options directly to the docker run command (e.g., to delete a container on exit with --rm).
  • Ephemeral Port Forwarding: Run --forward-port PORT, HOST_PORT:CONTAINER_PORT (default bind 0.0.0.0), or BIND:HOST_PORT:CONTAINER_PORT—and repeat the flag as needed—to spin up standalone socat bridges to a running sandbox until Ctrl+C.
  • Discoverable Container IP: The script prints the container IP on launch, so you can use it directly without running --set-hostname when you just need the address.
  • State Management: List running containers, list every entry in state.json, inspect one entry, or forget one entry from the state file without removing the Docker container.

Prerequisites

Before using the script, ensure you have the following tools installed on your system:

  • Docker: The engine for creating and running containers.
  • jq: For command-line JSON processing.
  • coreutils: Provides realpath, basename, cut, etc.
  • crc32: For generating short hashes (may be in libarchive-tools on some Linux distributions).
  • socat (optional): Required only when using --forward-port to proxy ports from the host to the container.

Usage

The cuybox.sh script must be executable (chmod +x cuybox.sh).

  1. Start a sandbox in the current directory:

    ./cuybox.sh
  2. Start a sandbox for a specific directory:

    ./cuybox.sh /path/to/your/project
  3. Use a custom tag for the container name:

    ./cuybox.sh /path/to/your/project my-special-tag
  4. Force host user setup: The container configures a matching user when it is created. Re-run the setup on demand with the optional flag:

    ./cuybox.sh /path/to/your/project --setup-user
  5. Attach with a custom program: By default, cuybox.sh attaches with byobu. Use --program to run another installed program directly, such as bash.

    ./cuybox.sh --program bash /path/to/your/project
  6. Pass additional parameters to Docker: To create a container that gets deleted upon exit (non-persistent behavior), use the --rm flag.

    ./cuybox.sh /path/to/your/project --rm

    To pass environment variables:

    ./cuybox.sh . -e MY_VARIABLE=my_value
  7. Forward a port from an already-running sandbox (requires socat): First, start the sandbox normally so the container is running. In another terminal, run the forwarding command and leave it running; stop it at any time with Ctrl+C. A lone PORT maps 0.0.0.0:PORT -> container:PORT, HOST_PORT:CONTAINER_PORT lets you choose different ports, and BIND:HOST_PORT:CONTAINER_PORT lets you constrain the host interface. You can repeat the flag to forward multiple ports, and the script will refuse to run if the container is stopped.

    ./cuybox.sh --forward-port 8080 /path/to/your/project
    ./cuybox.sh --forward-port 8080:3000 /path/to/your/project
    ./cuybox.sh --forward-port 127.0.0.1:9000:9000 /path/to/your/project
  8. Exit the sandbox: Simply type exit or press Ctrl+D.

  9. List sandboxes and manage recorded state: List only running containers by their Docker name and project path. The current working directory is marked when it matches an entry.

    ./cuybox.sh --list

    List every entry recorded in state.json, including stopped or missing containers. The listed ID is normally the generated container name (tag-hash-index).

    ./cuybox.sh --list-all

    Show one entry by its listed ID:

    ./cuybox.sh --show my-project-abcd-0

    Forget one entry from state.json by its listed ID. This does not remove the Docker container itself.

    ./cuybox.sh --forget my-project-abcd-0
  10. Install optional tools inside a sandbox: Run the catalog command from inside the sandbox. With no arguments it also lists the available items.

    cuybox-install list
    cuybox-install install NAME
    cuybox-install install codebase-memory-mcp

    Each item has its own installer script and is installed only when requested. Re-running an installer updates or repairs that item. The codebase-memory-mcp installer installs the npm package for the current user and runs its agent configuration command; restart active coding-agent sessions afterward.

How It Works

  • Dockerfile: Defines an Ubuntu-based environment with nvm, Node.js v22, and tini as PID 1. The container idles with tail -f /dev/null, so stop and start operations remain fast.
  • opencode-defaults.json: Supplies language-agnostic watcher.ignore defaults for JavaScript/TypeScript, Java, C/C++, Rust, Go, Erlang/Elixir, Python, .NET, PHP, Ruby, Swift, Dart, Android, and common tooling. Host-user setup merges these defaults into the user's global OpenCode config without removing existing settings.
  • cuybox.sh: This is the orchestrator that:
    1. Parses arguments to separate script inputs from Docker options.
    2. Calculates the absolute path of the directory and generates a 4-character crc32 hash.
    3. Queries the config file in $XDG_CONFIG_HOME/cuybox/state.json (or ~/.config/cuybox/state.json) to determine the container's index, avoiding collisions.
    4. Generates a unique and persistent name for the container.
    5. Checks if the develcuy/cuybox:latest Docker image exists and, if not, builds it.
    6. Creates the container on first run, runs the host-user setup once (or when --setup-user is passed), and then executes the attach program (byobu by default) inside the running container.
    7. Provides management commands (--list, --list-all, --show, and --forget) without starting sandbox setup. --list filters recorded entries using the current Docker state.
  • cuybox-install: Discovers optional installer scripts under tools/, lists them, and runs only the item explicitly requested by the sandbox user. Each executable installer must support --description and be safe to run repeatedly.

Customization

To add more tools or change the Node.js version, simply edit the Dockerfile and remove the local develcuy/cuybox:latest image (docker rmi develcuy/cuybox:latest). The next time you run cuybox.sh, the image will be rebuilt with your changes.

About

Containerized development sandbox manager with isolated, persistent Docker environments per project directory

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages