← All examples
Agent Harnesses low risk dockercode-reviewsandboxing

Agent Review Workspace (Docker)

One file, one command: meriadoc generates the Dockerfile, builds the sandbox, and launches the agent inside it — not three artifacts you stitch together by hand.

Replaces: a Dockerfile + a run script + a spec file you keep in sync by hand

Why the spec file alone isn’t enough

agent.enabled: false on a task removes it from what meriadoc advertises over MCP — it does not, by itself, stop anything. If the agent calling meriadoc also has its own native shell tool (most coding agents do), it doesn’t need meriadoc’s commit task at all; it can just run git commit directly. This isn’t hypothetical — it’s a filed bug against a major agent CLI (“MCP tools don’t respect sandboxing,” openai/codex#7635): a tool hidden at the MCP layer is trivially bypassed by any other tool the same agent process has access to. The fix is running the entire agent process, not just meriadoc, inside a boundary that makes the disallowed action physically impossible.

One file does the whole job

meriadoc isn’t just describing the sandbox here — it builds and launches it. sandbox-build writes the Dockerfile (and a discovery config for the container’s own meriadoc) to a throwaway build context and builds the image; sandbox-start runs it. meriadoc job sandbox-review does both in one command. The review policy — what the agent is actually allowed to call once it’s inside — lives in the same file as the tasks it protects, exactly like a real project’s meriadoc.yaml would.

version: v1

tasks:
  # ── Policy: what the agent may do once it's inside the sandbox ──
  # In a real project these sit alongside your normal build/test/deploy
  # tasks — this is just the review-relevant subset.

  status:
    description: "Show working tree status"
    agent:
      risk_level: low
    cmds:
      - git status

  diff:
    description: "Show uncommitted changes"
    agent:
      risk_level: low
    cmds:
      - git diff

  log:
    description: "Show recent commit history"
    agent:
      risk_level: low
    cmds:
      - git log --oneline -20

  run-tests:
    description: "Run the test suite"
    agent:
      risk_level: low
    cmds:
      - npm test

  commit:
    description: "Commit changes (human only — not exposed to the review agent)"
    agent:
      enabled: false
    cmds:
      - git commit

  # ── Sandbox: meriadoc builds and launches the container that enforces the policy above ──

  sandbox-build:
    description: "Build the agent-review sandbox image for this project"
    env:
      AGENT_CLI_PATH:
        type: filepath
        required: true
      MERIADOC_BIN_PATH:
        type: filepath
        default: "/usr/local/bin/meriadoc"
    preconditions:
      - cmds:
          - docker --version
        on_failure:
          continue: false
          cmds:
            - echo "docker not found. Install Docker Desktop from https://www.docker.com/products/docker-desktop"
    cmds:
      - |
        set -e
        BUILD_DIR=$(mktemp -d)
        cp "$MERIADOC_BIN_PATH" "$$BUILD_DIR/meriadoc"
        cp "$AGENT_CLI_PATH" "$$BUILD_DIR/agent"
        cat > "$$BUILD_DIR/config.yaml" <<'CONFIG_EOF'
        discovery:
          roots:
            - path: /workspace
              enabled: true
        CONFIG_EOF
        cat > "$$BUILD_DIR/Dockerfile" <<'DOCKERFILE'
        FROM debian:bookworm-slim
        RUN apt-get update && apt-get install -y --no-install-recommends \
              git nodejs npm \
            && rm -rf /var/lib/apt/lists/*
        COPY meriadoc /usr/local/bin/meriadoc
        COPY agent /usr/local/bin/agent
        COPY config.yaml /etc/meriadoc/config.yaml
        RUN chmod +x /usr/local/bin/meriadoc /usr/local/bin/agent
        ENV MERIADOC_CONFIG=/etc/meriadoc/config.yaml
        WORKDIR /workspace
        DOCKERFILE
        docker build -t agent-review-sandbox "$$BUILD_DIR"
        rm -rf "$$BUILD_DIR"
        echo "Built agent-review-sandbox"

  sandbox-start:
    description: "Launch the agent inside the sandbox — network-less, read-only repo mount"
    cmds:
      - |
        docker run --rm -it \
          --network none \
          --read-only \
          --tmpfs /tmp \
          -v "$(pwd)":/workspace:ro \
          agent-review-sandbox \
          agent --mcp-server "meriadoc serve"

jobs:
  sandbox-review:
    description: "Build (if needed) and start a sandboxed review session for this project"
    tasks:
      - sandbox-build
      - sandbox-start

Run it

meriadoc job sandbox-review --env AGENT_CLI_PATH=/usr/local/bin/claude

AGENT_CLI_PATH is the one thing meriadoc can’t know for you — point it at your agent’s actual binary (the Claude Code CLI, Aider, Codex CLI, etc.) and everything else — the Dockerfile, the container’s own discovery config, the build, the run — is generated and executed by meriadoc itself. run-tests needs your dependencies (e.g. node_modules) already installed in the repo before you run this, since /workspace is mounted read-only inside the container — there’s no npm install step to fall back on. commit is unreachable two ways: meriadoc won’t offer it, and even a direct git commit from the agent’s own shell hits a read-only filesystem.

Re-running meriadoc job sandbox-review after the first time is fast — Docker’s layer cache means sandbox-build mostly just confirms nothing changed.