Skip to content
Runtime

How to run Gemini CLI in a cloud sandbox

Install @google/gemini-cli with npm in a Linux microVM, keep the Gemini key as a secret, run gemini -p with --approval-mode yolo.

Runtime lets Gemini CLI run with every approval switched on, while your Google key stays outside the machine. Each sandbox is a Firecracker microVM with its own Linux kernel, Ubuntu 24.04 and Node.js 24. That meets Gemini CLI's requirement of Node.js 20 or later. The sandbox holds only a placeholder for GEMINI_API_KEY. The host's proxy swaps in the real key only on requests to Google's Gemini API, and nowhere else. While the agent waits on the model, a 2 vCPU, 4 GiB sandbox bills $0.03125 an hour. Gemini CLI 0.65.0 was the current npm release on 25 October 2026.

Goal Where Gemini CLI runs How it reaches Runtime
Let the agent change a repo with full shell access Inside a sandbox The SDK drives it from your code
Give Gemini CLI on your laptop a safe place to run code On your machine Runtime's MCP server, as a tool set

Why yolo mode needs a sandbox

In headless mode, nobody is present to approve a shell command. A useful run therefore needs --approval-mode yolo. Google's CLI reference describes this mode as auto-approving all actions. On a laptop or a CI runner, that means the model can run anything the user can. In a Runtime sandbox, the blast radius is one disposable virtual machine. It has its own kernel and no route to your network. Its outbound traffic is limited to the hosts you list. It holds no real credential on its disk.

Keep the Gemini key out of the sandbox

Gemini CLI reads an AI Studio key from GEMINI_API_KEY. Store it once as a Runtime secret tied to the Gemini API's host:

Terminalprintf %s "$GEMINI_API_KEY" | npx withruntime secrets set GEMINI_API_KEY --host generativelanguage.googleapis.com

From then on, every sandbox in your account starts with GEMINI_API_KEY set to a placeholder such as rtsec_3f9c…. The proxy adds the real key to the URL or headers of HTTPS requests to generativelanguage.googleapis.com only. So an agent that is tricked into posting its environment elsewhere sends a string that unlocks nothing (secrets sandboxes never see).

Run a task and collect the diff

TypeScriptimport { writeFile } from "node:fs/promises";import { Sandbox } from "withruntime";const repo = "https://github.com/your-org/your-repo";const task = "Add input validation to the signup handler and write a test for it.";await using sbx = await Sandbox.create({ diskMiB: 8192, timeoutSeconds: 3600 });const setup = { check: true, timeoutMs: 600_000 } as const;await sbx.exec("npm install -g --prefix /workspace/.local @google/gemini-cli", setup);await sbx.exec(["git", "clone", "--depth", "1", repo, "/workspace/app"], setup);// Only the Gemini API and the npm registry are reachable from here.await sbx.network.set({  internet: true,  allow: ["generativelanguage.googleapis.com", "registry.npmjs.org"],});const run = await sbx.exec(  ["gemini", "-p", task, "--approval-mode", "yolo", "--skip-trust", "--output-format", "json"],  { cwd: "/workspace/app", timeoutMs: 1_800_000, onStderr: (text) => process.stderr.write(text) },);const report = JSON.parse(run.stdout);console.log(run.exitCode, report.response, report.stats);await sbx.exec("git add -A && git diff --cached > /workspace/gemini.patch", {  cwd: "/workspace/app",  check: true,});await writeFile("gemini.patch", await sbx.files.readText("/workspace/gemini.patch"));
Pythonimport sys, jsonfrom withruntime import Sandboxrepo = "https://github.com/your-org/your-repo"task = "Add input validation to the signup handler and write a test for it."with Sandbox.create(disk_mib=8192, timeout_seconds=3600) as sbx:    sbx.exec("npm install -g --prefix /workspace/.local @google/gemini-cli",             check=True, timeout_ms=600_000)    sbx.exec(["git", "clone", "--depth", "1", repo, "/workspace/app"],             check=True, timeout_ms=600_000)    sbx.network.set(internet=True,                    allow=["generativelanguage.googleapis.com", "registry.npmjs.org"])    run = sbx.exec(        ["gemini", "-p", task, "--approval-mode", "yolo", "--skip-trust",         "--output-format", "json"],        cwd="/workspace/app", timeout_ms=1_800_000, on_stderr=sys.stderr.write,    )    report = json.loads(run.stdout)    print(run.exit_code, report["response"], report["stats"])    sbx.exec("git add -A && git diff --cached > /workspace/gemini.patch",             cwd="/workspace/app", check=True)    with open("gemini.patch", "w") as file:        file.write(sbx.files.read_text("/workspace/gemini.patch"))

Notes on the run:

  • The install puts gemini in /workspace/.local/bin. That directory is the first one on the sandbox's PATH. No sudo is needed.
  • -p forces non-interactive mode. The task is passed as one array element, so no shell reads its quotes.
  • --skip-trust trusts the checkout for this session, so the folder-trust check never waits for an answer.
  • --output-format json prints one object. response holds the final answer, and stats holds the token use and latency.
  • The patch is written to a file and read back. This keeps a large change clear of the 64 KiB limit on command output.

Headless reference

From Google's headless and CLI reference pages, read on 25 October 2026:

Flag or code Meaning
-p, --prompt Runs one prompt without the terminal UI
--approval-mode yolo Approves every tool call; auto_edit approves edits only
--yolo, -y Deprecated spelling of the same
--output-format json One object with response, stats and error
--output-format stream-json JSONL events: init, message, tool_use, result
--include-directories a,b Adds more folders to the workspace
Exit 0, 1, 42, 53 Success, API error, bad input, turn limit exceeded

Branch on the exit code in your host code. A 53 means the task needs more turns. It does not mean the model failed. For a follow-up task on the same checkout, pause the sandbox between runs. Files, memory and processes survive, and compute billing stops.

Let Gemini CLI call Runtime

In the reverse setup, Gemini CLI stays on your own machine and hands its code execution to Runtime. Add the MCP server once for your user:

Terminalgemini mcp add --scope user runtime npx -y withruntime mcp

That writes an entry to ~/.gemini/settings.json. To edit the file by hand, add this:

JSON{  "mcpServers": {    "runtime": { "command": "npx", "args": ["-y", "withruntime", "mcp"] }  }}

The first tool call prints a link and a short code. Approve Connect agent in the browser. The full tool list then loads, and the file holds no key (MCP). A laptop already signed in with npx withruntime login skips that step. Gemini CLI also accepts remote servers by httpUrl. https://api.withruntime.com/mcp works with browser sign-in instead of the bridge (remote connection).

Tool What Gemini CLI can do with it
runtime_sandboxes_create Start a microVM and wait until it is running
runtime_sandboxes_exec Run a command and read its exit code and output
runtime_sandboxes_interpreter_run Keep a Python or JavaScript session with charts
runtime_sandboxes_network Cut the sandbox's internet or narrow it to a list
runtime_sandboxes_manage Pause, wake, extend or stop it

What a run costs

CPU is billed on use at $0.025 per vCPU-hour, with a floor of a twentieth of a vCPU. Memory is billed at $0.0075 per GiB-hour of what you reserve. For 2 vCPUs and 4 GiB, that is $0.03125 an hour while Gemini thinks. It rises to $0.08 an hour only while both cores run tests (pricing). Google bills the tokens on your key. Every account has 100 free hours of a 1 GB machine in its first 30 days, with no card needed:

Terminalnpx withruntime sandboxes run -- node --version

The same pattern for other agents is in Codex and Qwen Code, which began as a fork of Gemini CLI. A sandbox for coding agents covers running many tasks side by side.

Sources

Checked 25 October 2026.

Facts on this page were checked on 25 October 2026.

Related.

100 free hoursin your first 30 days.

of a 1 GB machine

  • No credit card
  • Four sandboxes at once, 2 vCPU and 4 GiB each
  • Then prepaid credit from $10, no plan fee
Start free, no card
Start free, no card