This is an experimental fork of Gemini CLI that introduces Docker Sandbox Mode for isolated execution of LLM-initiated operations.
The original Gemini CLI executes all LLM-initiated operations (file reads/writes, shell commands) directly on the host machine. While the CLI has safety mechanisms like approval modes and allowlists, there's an inherent security concern when an AI agent has direct access to your filesystem and can execute arbitrary commands.
Docker Sandbox Mode addresses this by:
- Isolating LLM operations in a Docker container
- Preserving the native CLI experience - the CLI itself runs on your host
- Maintaining compatibility with existing workflows and directory mounting
- Providing an additional security layer for teams that require stronger isolation
This implementation demonstrates how to integrate Docker's sandbox capabilities
(docker sandbox run) with an AI coding agent, serving as a reference
architecture for secure LLM tool execution.
Docker Sandbox Mode uses a split architecture: the Gemini CLI runs on the host while LLM-initiated operations execute in an isolated Docker container.
┌─────────────────────────────────────────────────────────────┐
│ HOST MACHINE │
│ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Gemini CLI Process │ │
│ │ • Configuration & Settings (~/.gemini/) │ │
│ │ • Authentication & OAuth │ │
│ │ • UI/Terminal Rendering │ │
│ │ • Extension Management │ │
│ │ • Container Lifecycle Management │ │
│ └─────────────────┬─────────────────────────────────────┘ │
│ │ │
│ │ docker exec <container-id> <command> │
│ ↓ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Docker Sandbox Container (Long-Running, Detached) │ │
│ │ • File Operations (read/write) │ │
│ │ • Shell Command Execution │ │
│ │ • Network Operations (future) │ │
│ │ • Mounted: /Users/shelajev/project → /Users/... │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
The following operations run directly on the host and are not sandboxed:
-
CLI Initialization
- Loading settings from
~/.gemini/settings.json - Reading OAuth credentials
- Loading extensions and custom commands
- Reading
.envfiles - Managing session state and history
- Loading settings from
-
Container Management
- Starting the Docker sandbox:
docker sandbox run --detached gemini - Stopping the container on CLI exit
- Health checks and container status monitoring
- Starting the Docker sandbox:
-
UI Rendering
- Terminal output and interactive prompts
- Progress indicators and status updates
- User input handling
-
File Discovery
- Finding
GEMINI.mdfiles - Scanning for extension directories
- Project structure analysis (synchronous glob operations)
- Finding
The following LLM-initiated operations run inside the Docker container:
-
File Operations
- ✅ Reading files (text files via ReadFile tool)
- ✅ Writing files (WriteFile tool, Edit tool, SmartEdit tool)
- ✅ Reading binary files (images, PDFs, audio, video)
⚠️ File stat operations (currently use host as fallback - TODO)
-
Shell Operations
- ✅ All shell commands executed via Shell tool
- ✅ Background processes and command streaming
- ✅ Working directory context preserved
-
Binary Operations
- ✅ Image processing for multimodal LLM input
- ✅ PDF reading for document analysis
- Build it:
npm install
npm run build
-
CLI Starts on Host
GEMINI_SANDBOX=docker-sandbox node bundle/gemini.js # or node bundle/gemini.js --sandbox docker-sandbox -
Container Lifecycle
- CLI executes:
docker sandbox run --detached gemini - Container starts and runs in the background
- Container ID is stored for subsequent operations
- Container persists for the entire CLI session
- CLI executes:
-
LLM Operation Flow
User: "create a file hello.txt" ↓ LLM generates tool call: WriteFile(path="hello.txt", content="...") ↓ WriteFile Tool → config.getFileSystemService() ↓ SandboxedFileSystemService (detects docker-sandbox mode) ↓ DockerSandboxedFileOperations.writeTextFile() ↓ Executes: docker exec <container-id> sh -c 'cat > hello.txt << EOF...' ↓ File created inside container (and visible on host due to volume mount) -
Session Cleanup
- On CLI exit, container is stopped:
docker stop <container-id> - Container is preserved for potential reuse by
docker sandbox
- On CLI exit, container is stopped:
- Node.js v20 or higher
- Docker with
docker sandboxcommand support - macOS, Linux, or Windows (with WSL2)
-
Clone this repository
git clone https://github.com/YOUR_USERNAME/gemini-cli.git cd gemini-cli -
Install dependencies
npm install
-
Build the project
npm run build
-
Create the bundle
npm run bundle
The compiled CLI will be available at
bundle/gemini.js
GEMINI_SANDBOX=docker-sandbox node bundle/gemini.jsGEMINI_SANDBOX=docker-sandbox npm run start# Link for development
npm link
# Run from anywhere
GEMINI_SANDBOX=docker-sandbox geminiSet the environment variable permanently:
export GEMINI_SANDBOX=docker-sandbox
geminiOr configure in ~/.gemini/settings.json:
{
"tools": {
"sandbox": "docker-sandbox"
}
}When running with DEBUG=1, you should see:
DEBUG=1 GEMINI_SANDBOX=docker-sandbox geminiExpected output:
Starting Docker sandbox container...
Executing: docker sandbox run --detached gemini
Docker sandbox container started: 026d5a7bf7ae...
docker-sandbox mode: CLI runs on host, operations run in container
[Docker Sandbox] Writing file: /path/to/file.txt (42 bytes)
[Docker Sandbox] File written successfully
[Docker Sandbox] Executing shell command: ls -la
Try these commands to verify operations run in the container:
# 1. Check filesystem isolation
> list the contents of the root directory
# Should show Linux directories (bin, etc, lib, usr) not macOS (Applications, Library)
# 2. Test file operations
> create a file called test.txt with content "hello from docker"
> read the file test.txt
# 3. Test shell commands
> run the command "uname -a"
# Should show Linux kernel, not Darwin/WindowsThis is an experimental implementation with the following caveats:
-
Incomplete Coverage
- Some LLM-initiated operations may still execute on the host
- Network operations are not yet fully sandboxed
- File stat operations use host as fallback
-
Not Production Ready
- No formal security audit has been performed
- The codebase has not been comprehensively verified for complete sandboxing
- Edge cases and error handling may be incomplete
-
Performance
- Each operation requires
docker exec, adding latency - Binary file operations may be slower due to encoding/decoding
- Each operation requires
-
Compatibility
- Requires
docker sandboxcommand (Docker Desktop extension) - May not work with all Docker configurations
- Some host-specific tools may not be available in the container
- Requires
This implementation serves as a proof of concept showing:
- ✅ How to integrate container isolation with an LLM agent CLI
- ✅ Split architecture: native CLI experience + sandboxed operations
- ✅ Minimal changes to existing tool implementations
- ✅ Reuse of Docker's native sandbox capabilities
It is not intended as a complete security solution but rather as a reference implementation for teams building similar systems.
The sandbox implementation introduces several key abstractions:
SandboxedFileOperations- Abstract interface for file operationsSandboxedShellOperations- Abstract interface for shell operationsSandboxedNetworkOperations- Abstract interface for network operations
DockerSandboxManager- Container lifecycle managementDockerSandboxedFileOperations- File operations viadocker execDockerSandboxedShellOperations- Shell execution viadocker exec
SandboxedFileSystemService- BridgesFileSystemService→ sandboxed ops- Tools (ReadFile, WriteFile, Shell) use
config.getSandboxedXXXOperations()
-
No CLI Relaunch
- Traditional sandbox modes (docker, podman) relaunch the entire CLI inside the container
- Docker sandbox mode keeps CLI on host, only sandboxes individual operations
- Avoids the exit code 42 relaunch loop entirely
-
Long-Running Container
- Container starts once at CLI initialization
- Persists for entire session
- Reused across multiple operations for performance
-
Preserved Path Semantics
- Working directory mounted at identical path in container
- Absolute paths work identically in both contexts
- Simplifies tool implementations
-
Separation of Concerns
SystemFileOperations- CLI's own files (settings, credentials) on hostSandboxedFileOperations- LLM operations in container- Clear boundary prevents chicken-and-egg problems
Apache License 2.0 - Same as upstream Gemini CLI
See LICENSE file for details.
Experimental Fork