Four agent configurations, one model, 25 SWE-bench Verified instances. Resolve rates: 19, 19, 21, 19 of 25. The spread is inside measured run-to-run variance, so this run does not rank them.
| Agent | Resolved | Avg sec | Avg tool calls | Avg output tokens | Avg cost | Total cost |
|---|---|---|---|---|---|---|
| Claude Code | 19 / 25 | 110 | 17.6 | 4,975 | $0.26 | $6.52 |
| localcode (Smart Agent off) | 19 / 25 | 167 | 29.8 | 9,434 | not reported | not reported |
| localcode (Smart Agent on) | 21 / 25 | 139 | 29.5 | 7,586 | not reported | not reported |
| opencode | 19 / 25 | 521 | 26.8 | 6,780 | $0.29 | $7.34 |
Qualifications:
Instance ids link to the upstream pull request that fixed the issue, which is the reference each patch was scored against.
| Instance | Repository | Difficulty | Claude Code | localcode (Smart Agent off) | localcode (Smart Agent on) | opencode |
|---|---|---|---|---|---|---|
astropy__astropy-13453 | astropy/astropy | 15 min - 1 hour | pass | pass | pass | pass |
astropy__astropy-7336 | astropy/astropy | <15 min fix | pass | pass | pass | pass |
django__django-12193 | django/django | <15 min fix | fail | fail | fail | fail |
django__django-13809 | django/django | 15 min - 1 hour | pass | pass | pass | stalled |
django__django-16100 | django/django | <15 min fix | pass | pass | pass | pass |
matplotlib__matplotlib-24026 | matplotlib/matplotlib | 15 min - 1 hour | pass | pass | pass | stalled |
matplotlib__matplotlib-24570 | matplotlib/matplotlib | <15 min fix | pass | pass | pass | pass |
mwaskom__seaborn-3187 | mwaskom/seaborn | 15 min - 1 hour | pass | fail | pass | pass |
pallets__flask-5014 | pallets/flask | <15 min fix | pass | pass | pass | pass |
psf__requests-1142 | psf/requests | <15 min fix | pass | pass | pass | stalled |
psf__requests-1766 | psf/requests | <15 min fix | pass | pass | pass | pass |
psf__requests-2931 | psf/requests | 15 min - 1 hour | pass | fail | pass | pass |
pydata__xarray-3095 | pydata/xarray | 15 min - 1 hour | pass | pass | pass | pass |
pydata__xarray-3993 | pydata/xarray | 1-4 hours | pass | pass | pass | pass |
pydata__xarray-4356 | pydata/xarray | <15 min fix | pass | pass | pass | stalled |
pylint-dev__pylint-4551 | pylint-dev/pylint | 1-4 hours | fail | pass | pass | pass |
pylint-dev__pylint-7080 | pylint-dev/pylint | 15 min - 1 hour | fail | fail | fail | pass |
pytest-dev__pytest-10051 | pytest-dev/pytest | 15 min - 1 hour | pass | pass | pass | pass |
pytest-dev__pytest-10356 | pytest-dev/pytest | 1-4 hours | fail | fail | pass | stalled |
pytest-dev__pytest-5631 | pytest-dev/pytest | 15 min - 1 hour | pass | pass | pass | pass |
scikit-learn__scikit-learn-10844 | scikit-learn/scikit-learn | 15 min - 1 hour | pass | pass | pass | pass |
scikit-learn__scikit-learn-25102 | scikit-learn/scikit-learn | 1-4 hours | pass | pass | pass | pass |
scikit-learn__scikit-learn-25747 | scikit-learn/scikit-learn | 15 min - 1 hour | fail | pass | fail | pass |
sphinx-doc__sphinx-8056 | sphinx-doc/sphinx | 15 min - 1 hour | pass | fail | pass | pass |
sympy__sympy-13798 | sympy/sympy | 15 min - 1 hour | fail | pass | fail | pass |
django__django-12193SplitArrayWidget.CheckboxInput.get_context mutating the attrs dictionary passed to it.CheckboxInput.get_context.CheckboxInput directly, so the call-site change does not pass it.- self.widget.get_context(name + '_%s' % i, widget_value, final_attrs)
+ self.widget.get_context(name + '_%s' % i, widget_value, final_attrs.copy())
All four configurations produced the same incorrect fix. The shared model is a possible cause, but this run does not isolate the cause.
Two phases, run separately:
git diff is kept.test_patch, overwriting any test file the agent touched, then runs FAIL_TO_PASS and PASS_TO_PASS. Editing tests to make them pass therefore gains nothing.Conditions held equal across all four configurations:
output_config.effort: high and thinking: adaptive; localcode: thinking: adaptive, no effort field; opencode: neither field. Omitting the thinking parameter was confirmed against the API to still produce adaptive thinking on this model, and an omitted effort takes the documented default of high, so the three resolve to the same setting. The API does not echo effort in responses, so that last step rests on the documented default rather than on a measurement here.max_tokens: 64,000 for Claude Code, 32,768 for localcode, 32,000 for opencode. No patch in this run was truncated by it.All three tools keep state in the home directory: credentials, plugins, hooks, custom commands, memory index, session list. The machine used here carried an opencode configuration with a local-model provider and a plugin, and a Claude Code installation signed in to a subscription. Mechanism:
AGENT_HOME=/tmp/agenthome
rm -rf "$AGENT_HOME"; mkdir -p "$AGENT_HOME/.config/opencode"
cp /bench/opencode.json "$AGENT_HOME/.config/opencode/opencode.json"
chown -R "$BENCH_USER" "$AGENT_HOME" "$REPO" "$OUT"
setpriv --reuid=... --regid=... --init-groups \
env HOME="$AGENT_HOME" PATH=/agents/node/bin:... \
ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
python /bench/runagent.py --out "$OUT" -- "$@"
--rm from the stock instance image, so no state survives a run or arrives from the previous one.HOME set in the environment passed to the agent process rather than inherited, so passwd-based and $HOME-based lookups resolve to the same empty directory.swebench/sweb.eval.x86_64.<instance>.Characteristics, from opencode's own event stream:
stderr empty: no exception, no rate-limit message, no reconnect attempt.Result: +2 instances, and 29 seconds faster per run, at the same number of tool calls. Not separable from noise at this sample size.
What the switches enable:
Confounds and observations:
seaborn-3187, requests-2931, pytest-10356 and sphinx-8056; Smart Agent off resolved scikit-learn-25747 and sympy-13798.input_tokens: 2 rather than the context sent, so that configuration has no comparable input-token total.