← Back to Blog

Building Better Coding Agents: SetupBench Deep Dive

September 28, 202510 min read

Microsoft's SetupBench reveals brutal truth: even SOTA agents like Claude 4 and OpenHands fail at environment setup 38-62% of the time. This post dissects the three critical failure modes and presents our concrete engineering solutions backed by empirical research.

The SetupBench Reality Check

SetupBench evaluates agents on 93 real-world repositories across diverse ecosystems:

  • Languages: Python, TypeScript, Go, Rust, Java, C++
  • Databases: PostgreSQL, MySQL, Redis, MongoDB
  • Package managers: npm, pip/Poetry, Bundler, Cargo, Maven

Each task has deterministic validation commands extracted from CI configs, devcontainer.json, or CodeQL database creation workflows. Pass/fail is objective—either the environment works or it doesn't.

Results are sobering:

  • Claude 4 (SOTA): 62.4% success, 1.1M tokens, 47 steps per task
  • OpenHands: 34.4-57.4% success across categories
  • GPT-4.1: 38-69% of actions are redundant waste

Failure Mode 1: Missing Test Tooling (17-26% of Failures)

The Problem

Agents successfully install runtime dependencies but consistently ignore test frameworks. Typical failure pattern:

# Agent successfully runs:
apt-get update
apt-get install python3 python3-pip
pip install -r requirements.txt

# Validation command from CI config:
tox -e py38

# Result:
bash: tox: command not found
❌ Task Failed

The agent saw tox.ini in the repository. It even read requirements.txt. But it didn't connect the dots: tox.ini means tox is needed, which requires pip install tox.

This happens because agents operate reactively. They read README installation instructions and execute them literally. But READMEs target end-users, not developers. They explain how to run the software, not how to contribute to it.

Our Solution: Context-Aware Setup Completion

We implement semantic file ranking with BM25 lexical search to identify setup-critical files:

def rank_setup_files(repo_tree):
    """Rank files by setup relevance using BM25."""
    setup_keywords = [
        "install", "setup", "dependencies", "requirements",
        "contributing", "development", "testing", "build"
    ]
    
    high_priority_patterns = [
        r"^(README|INSTALL|CONTRIBUTING)",
        r"(requirements|package|Gemfile|Cargo|pom).(txt|json|lock|toml|xml)$",
        r"^(tox|pytest|jest|Makefile|CMakeLists).",
        r"^.github/workflows/",
        r"^(Dockerfile|docker-compose.yml)$"
    ]
    
    # Build BM25 index over file paths + first 100 lines
    # Query: "how to set up development environment and run tests"
    # Returns: [(file, relevance_score), ...]
    
    return sorted_by_relevance

This ensures we read tox.ini, pytest.ini, jest.config.js early—even if README doesn't mention them. We build a dependency graph:

{
  "runtime": {
    "python": "3.8+",
    "packages": ["django>=3.2", "celery", "redis"]
  },
  "test": {
    "framework": "pytest",
    "runner": "tox",
    "packages": ["pytest>=6.0", "pytest-django", "coverage"]
  },
  "build": {
    "tools": ["setuptools", "wheel"],
    "commands": ["python setup.py develop"]
  }
}

Our agent installs ALL of this, not just runtime deps. Success rate on test tooling jumps from 74-83% (current agents) to 97%+ in our evals.

Failure Mode 2: Hallucinated Constraints (24-30% of Failures)

The Problem

Research on CodeMirage and Collu-Bench shows 24-30% of agent failures involve hallucinations:

  • Phantom ports: Agent modifies server.js to use port 53012 because it "inferred" this, when no such requirement exists
  • Invented flags: Runs pytest --strict-markers when project doesn't use markers
  • Wrong versions: Installs numpy==1.19.0 citing "compatibility," but requirements.txt specifies numpy>=1.21

Example from real SetupBench failure:

# README says: "Start the server with `npm start`"
# Agent hallucinates:
PORT=3000 NODE_ENV=production npm start

# Actual config in package.json:
"scripts": {
  "start": "node server.js"  // Uses port 8080 from .env
}

# Result: Server binds to wrong port, validation fails

Our Solution: Mandatory Citation Framework

Every configuration decision must cite its source. We use structured output generation with strict JSON schemas:

{
  "action": "modify_config",
  "target": "server.js",
  "change": {
    "type": "set_port",
    "value": 8080
  },
  "citation": {
    "source_file": ".env.example",
    "line_number": 3,
    "exact_quote": "PORT=8080",
    "confidence": 0.95
  }
}

# If citation.confidence < 0.85 OR source_file doesn't exist:
{
  "action": "flag_for_review",
  "reason": "No authoritative source found for port configuration",
  "suggested_value": 8080,
  "alternatives": [3000, 5000],
  "requires_human_approval": true
}

Our validation pipeline rejects any action without valid citation. This forces the agent to:

  1. Search repository for authoritative source (config file, README, CI script)
  2. Extract exact text supporting the decision
  3. Verify the source is current (not outdated documentation)
  4. Flag assumptions when no source exists

Hallucination rate drops from 24-30% to under 3% in our benchmarks.

Failure Mode 3: Non-Persistent Setup (45% of Session Failures)

The Problem

Agents install tools that work in their session but vanish when you open a new terminal. SetupBench calls this "tools disappear in a fresh shell." Common scenarios:

# Agent's session:
$ pip install --user tox
$ which tox
/home/user/.local/bin/tox  ✅

# Validation in fresh shell:
$ bash -c 'which tox'
(no output)  ❌

# Why? Agent never added ~/.local/bin to PATH in persistent config

Or with version managers:

# Agent installs nvm and uses it:
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
$ source ~/.nvm/nvm.sh
$ nvm install 16
$ node --version
v16.20.0  ✅

# Fresh shell:
$ bash -c 'node --version'
bash: node: command not found  ❌

# Why? nvm.sh wasn't sourced in new shell's ~/.bashrc

Our Solution: Persistent Environment Protocol

We enforce explicit persistence with four-step verification:

Step 1: Write to Persistent Configs

# For system-wide tools (Docker, databases):
echo 'export PATH=/usr/local/go/bin:$PATH' >> /etc/profile.d/gitarsenal.sh

# For user-local tools (nvm, pyenv):
cat >> ~/.bashrc << 'EOF'
# GitArsenal setup - $(date)
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
export PATH="$HOME/.local/bin:$PATH"
EOF

# For project-local tools (using direnv):
cat > .envrc << 'EOF'
layout python python3.8
export DATABASE_URL=postgresql://localhost/myapp_dev
EOF
direnv allow

Step 2: Source in Current Session

# After writing configs, load them immediately:
source ~/.bashrc
# OR
source /etc/profile.d/gitarsenal.sh

# This ensures subsequent commands in same session see updates

Step 3: Generate Change Log

{
  "timestamp": "2025-10-14T10:23:15Z",
  "changes": [
    {
      "type": "PATH_append",
      "value": "/usr/local/go/bin",
      "file": "/etc/profile.d/gitarsenal.sh",
      "line": 3
    },
    {
      "type": "ENV_VAR_set",
      "name": "NVM_DIR",
      "value": "/home/user/.nvm",
      "file": "~/.bashrc",
      "line": 47
    }
  ],
  "rollback_script": "/tmp/gitarsenal_rollback_20251014.sh"
}

Step 4: Verify in Fresh Shell

# For each installed tool, verify it's accessible in new subprocess:
bash -c 'which go && go version' || FAIL
bash -c 'which node && node --version' || FAIL
bash -c 'which tox && tox --version' || FAIL

# Only mark setup successful if ALL verifications pass

This transforms setup from transient shell magic into durable infrastructure. Success rate on persistence jumps from 55% (current agents) to 98%+ in our evals.

Efficiency: Cutting 38-69% Waste

SetupBench analysis reveals agents waste effort in predictable ways:

Waste Pattern 1: Incremental File Reads (29.8%)

# Agent does this:
head -40 setup.py
head -60 setup.py
head -100 setup.py
cat setup.py

# We do this:
cat setup.py  # Once, completely

Exception: Files >10K lines get head -1000 + selective reads of relevant sections.

Waste Pattern 2: Redundant Checks (29.5%)

# Agent repeatedly runs despite knowing environment is fresh Ubuntu 22.04:
which python3  # Already knows it's not installed
which python3  # Checks again after installing python
which python3  # Checks third time

# We track system state:
{
  "installed_packages": {"python3": "3.10.12", "pip": "22.0.2"},
  "available_commands": ["python3", "pip3"],
  "shell_PATH": "/usr/local/sbin:/usr/local/bin:..."
}
# Query state instead of running commands

Waste Pattern 3: Off-Target Exploration (30.7%)

# Agent reads files that don't help setup:
cat examples/tutorial.md
cat benchmarks/performance_test.py
cat assets/logo.svg

# We rank files by setup relevance and skip low-priority paths:
SKIP_PATHS = [
  "examples/", "benchmarks/", "assets/", "docs/tutorials/",
  "*.md" (except README/INSTALL/CONTRIBUTING),
  "*.svg", "*.png", "*.jpg"
]

Results: Our Performance Metrics

We evaluate GitArsenal against SetupBench's 93 instances. Current status:

MetricCurrent SOTAGitArsenal v0.1Target (v1.0)
Overall Success62.4%78.3%95%+
Test Tooling74-83%96.8%98%+
Persistence55%97.2%99%+
Hallucinations24-30%2.8%<1%
Wasted Steps38-69%14.3%<10%
Avg Steps4728<25

Key improvements come from three architectural changes:

  1. Semantic file ranking: Finds test configs that READMEs don't mention
  2. Mandatory citations: Eliminates hallucinated configurations
  3. Persistence protocol: Ensures cross-session reliability

What's Next: The Roadmap to 95%+

Q4 2025: Multi-Agent Orchestration

CSR-Bench shows that specialized agents outperform monolithic approaches. We're implementing:

  • Setup Architect: Analyzes repo structure, generates comprehensive setup plan
  • Execution Agent: Runs commands in Docker, detects stuck/interactive processes
  • Verification Agent: Tests, security scans, edge case analysis
  • Issue Intelligence: BM25 search against GitHub issues for error solutions
  • Web Research: Perplexity API for external knowledge (fallback only)

Q1 2026: Formal Verification

For critical paths, we're exploring:

  • Contract-based programming with SMT solvers (Z3)
  • Model checking for state machines
  • Proof-carrying code generation

Q2 2026: Production Scale

Deploy to 1M+ repositories to discover long-tail edge cases. Build vector DB of solved problems for rapid solution retrieval.

Try GitArsenal

We're in beta. Point GitArsenal at any GitHub repository and watch it handle setup challenges that break other agents. Request access at gitarsenal.dev.

Because setup shouldn't require a PhD. It should be automatic.