GitHub Docs

Overview

VibeCody provides two powerful operational modes: Watch Mode re-runs an agent task automatically whenever files change, and Sandbox Isolation runs agent tasks inside an OS-level container with restricted filesystem, network, and process access. These can be combined to create safe, continuous development loops where the AI reacts to your edits in a locked-down environment.

Time to complete: ~12 minutes

Prerequisites

  • VibeCLI 0.5.1 or later installed and on your PATH
  • At least one AI provider configured
  • For sandbox mode: Docker or Podman installed (or OpenSandbox for macOS native)
  • A project with source files and tests

Step-by-Step Walkthrough

Step 1: Basic watch mode

Watch mode monitors files and re-runs an agent task when changes are detected:

vibecli --watch --agent "Run the test suite and report failures"
vibecli 0.5.1 | Watch mode enabled
Watching: . (all files)
Agent task: "Run the test suite and report failures"

[Watch] Initial run...

[Agent] Running test suite...
[Tool: execute_command] cargo test
  Running 2,473 tests
  test result: ok. 2,473 passed; 0 failed

[Agent] All 2,473 tests pass. Watching for changes...

[Watch] Waiting for file changes... (Ctrl+C to stop)

Now edit a file in another terminal. The agent re-runs automatically:

[Watch] Changed: src/inventory.rs (modified)
[Watch] Re-running agent task...

[Agent] Detected change in src/inventory.rs. Running tests...
[Tool: execute_command] cargo test --lib inventory

  test inventory::tests::test_create ... ok
  test inventory::tests::test_list ... FAILED
  test inventory::tests::test_pagination ... ok

  failures:
    test_list expected 5 items but got 4

  test result: FAILED. 2 passed; 1 failed

[Agent] 1 test failure in inventory::tests::test_list.
  The test expects 5 items but gets 4. This is likely caused by
  the filter change on line 42 of src/inventory.rs where you added
  `status != "archived"`, which excludes one test fixture item.

  Fix: update the test to expect 4 items, or add a non-archived
  fixture item to maintain the count of 5.

[Watch] Waiting for file changes...

Step 2: Watch with glob filters

Limit which files trigger re-runs using --watch-glob:

vibecli --watch --agent "Run Rust tests and clippy" --watch-glob "**/*.rs"
vibecli 0.5.1 | Watch mode enabled
Watching: **/*.rs (Rust files only)
Agent task: "Run Rust tests and clippy"

[Watch] Initial run...
[Agent] Running cargo test and cargo clippy...
[Tool: execute_command] cargo test
  test result: ok. 2,473 passed; 0 failed
[Tool: execute_command] cargo clippy -- -D warnings
  Finished: 0 warnings, 0 errors

[Watch] Waiting for file changes... (ignoring non-Rust files)

Changes to .md, .toml, .tsx, or other non-Rust files are silently ignored.

Step 3: Sandbox mode basics

Run an agent task inside an isolated container:

vibecli --sandbox --agent "Analyze the project structure and suggest improvements"
vibecli 0.5.1 | Sandbox: enabled (Docker)
Container: vibecli-sandbox-f8a2c1d3
Filesystem: project mounted read-only at /workspace
Network: enabled (outbound only)
Timeout: 300s

[Agent] Analyzing project structure from sandbox...
[Tool: execute_command] find /workspace -type f -name "*.rs" | head -30
[Tool: read_file] /workspace/Cargo.toml
[Tool: read_file] /workspace/vibecli/vibecli-cli/src/main.rs

[Agent] Project structure analysis:
  - Workspace with 6 crates (well-organized monorepo)
  - 178+ Rust modules in vibecli-cli
  - Good separation: vibe-core, vibe-ai, vibe-lsp, vibe-extensions
  - Suggestion: Consider splitting vibecli-cli/src/ into feature-gated
    sub-crates to reduce compile times

[Sandbox] Container removed. Duration: 12s.

Step 4: Network-disabled sandbox

For maximum isolation, disable network access:

vibecli --sandbox --no-network --agent "Review src/auth.rs for security issues"
vibecli 0.5.1 | Sandbox: enabled (Docker, network disabled)
Container: vibecli-sandbox-b4e7d290
Filesystem: project mounted read-only at /workspace
Network: disabled (no outbound connections)
Timeout: 300s

[Agent] Reviewing src/auth.rs in isolated sandbox...
[Tool: read_file] /workspace/vibecli/vibecli-cli/src/auth.rs

[Agent] Security review of auth.rs:

  1. [OK] Token hashing uses SHA-256 with salt
  2. [OK] Rate limiting on login attempts (5/minute)
  3. [WARN] Line 84: Token expiry is set to 30 days — consider 24h
     with refresh tokens for sensitive operations
  4. [WARN] Line 112: Error message distinguishes "user not found"
     from "wrong password" — this leaks username existence
  5. [OK] CORS headers properly restricted to allowed origins

  2 warnings, 0 critical issues found.

[Sandbox] Container removed. Duration: 8s.

The AI could not phone home, exfiltrate code, or reach any external service during this run.

Step 5: Combine watch and sandbox

The most powerful configuration – continuous testing in an isolated environment:

vibecli --watch --sandbox --agent "Run tests" --watch-glob "**/*.rs"
vibecli 0.5.1 | Watch mode + Sandbox enabled
Watching: **/*.rs
Sandbox: Docker (network enabled, filesystem read-only)

[Watch] Initial run (spinning up sandbox)...
[Sandbox] Container: vibecli-sandbox-c9f1a3b5
[Agent] Running cargo test in sandbox...
[Tool: execute_command] cargo test
  test result: ok. 2,473 passed; 0 failed
[Sandbox] Container paused (kept warm for fast re-runs).

[Watch] Waiting for file changes...

  --- (you edit src/models.rs) ---

[Watch] Changed: src/models.rs (modified)
[Sandbox] Container resumed.
[Agent] Running affected tests...
[Tool: execute_command] cargo test --lib models
  test result: ok. 18 passed; 0 failed
[Sandbox] Container paused.

[Watch] Waiting for file changes...

The sandbox container is kept warm between runs for faster iteration. It is fully destroyed when you press Ctrl+C.

Step 6: Sandbox configuration

Fine-tune sandbox behavior in ~/.vibecli/config.toml:

[sandbox]
runtime = "docker"          # docker, podman, or opensandbox
timeout_seconds = 300
network = true
mount_mode = "read-only"    # read-only or read-write
memory_limit = "2g"
cpu_limit = 2
allowed_paths = ["/workspace", "/tmp"]
blocked_commands = ["rm -rf /", "curl", "wget"]

Or per-profile in ~/.vibecli/profiles/secure.toml:

[sandbox]
runtime = "docker"
network = false
mount_mode = "read-only"
memory_limit = "1g"

Step 7: Sandbox with write access

When you need the agent to actually modify files:

vibecli --sandbox --agent "Fix the failing test in src/models.rs"
vibecli 0.5.1 | Sandbox: enabled (Docker)
Filesystem: project mounted read-write at /workspace
Network: enabled

[Agent] Investigating test failure...
[Tool: execute_command] cargo test --lib models 2>&1
  test models::tests::test_serialize ... FAILED
  assertion: left == right
    left:  {"name":"item","qty":0}
    right: {"name":"item","quantity":0}

[Tool: read_file] /workspace/src/models.rs
[Agent] Found it -- the Serialize rename attribute uses "qty" but the
test expects "quantity".

[Tool: write_file] /workspace/src/models.rs (line 15: rename = "quantity")
[Tool: execute_command] cargo test --lib models
  test result: ok. 18 passed; 0 failed

[Agent] Fixed. The serde rename on line 15 was changed from "qty" to
"quantity" to match the expected JSON output.

[Sandbox] Container removed. Changes written to project directory.

How Sandbox Isolation Works

VibeCody uses the ContainerRuntime trait to abstract across 3 runtimes:

Runtime Platform Isolation Level Setup Required
Docker All Full container Docker installed
Podman Linux Rootless Podman installed
OpenSandbox macOS App Sandbox Xcode tools

The runtime provides 16 async methods including container creation, filesystem mounting, network policy, process limits, and cleanup. All agent tool calls are proxied through the container.

Demo Recording

{
  "meta": {
    "title": "Watch Mode & Sandbox Isolation",
    "description": "Automatic file watching with agent re-runs and OS-level sandbox isolation for safe AI execution.",
    "duration_seconds": 200,
    "version": "1.0.0"
  },
  "steps": [
    {
      "id": 1,
      "action": "shell",
      "command": "vibecli --watch --agent \"Run tests\" --watch-glob \"**/*.rs\" &",
      "description": "Start watch mode for Rust files",
      "delay_ms": 5000
    },
    {
      "id": 2,
      "action": "shell",
      "command": "echo '// trigger' >> src/lib.rs",
      "description": "Trigger a file change",
      "delay_ms": 8000
    },
    {
      "id": 3,
      "action": "shell",
      "command": "kill %1",
      "description": "Stop watch mode",
      "delay_ms": 1000
    },
    {
      "id": 4,
      "action": "shell",
      "command": "vibecli --sandbox --no-network --agent \"Review src/auth.rs for security issues\"",
      "description": "Run a sandboxed security review with no network",
      "delay_ms": 15000
    },
    {
      "id": 5,
      "action": "shell",
      "command": "vibecli --sandbox --agent \"Fix the failing test in src/models.rs\"",
      "description": "Run a sandboxed agent that writes fixes",
      "delay_ms": 12000
    }
  ]
}

What’s Next