commitarena 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- commitarena-0.1.1/.gitignore +15 -0
- commitarena-0.1.1/CHANGELOG.md +31 -0
- commitarena-0.1.1/LICENSE +21 -0
- commitarena-0.1.1/PKG-INFO +242 -0
- commitarena-0.1.1/README.es.md +219 -0
- commitarena-0.1.1/README.md +217 -0
- commitarena-0.1.1/docs/src/social-preview.html +17 -0
- commitarena-0.1.1/pyproject.toml +58 -0
- commitarena-0.1.1/src/commitarena/__init__.py +40 -0
- commitarena-0.1.1/src/commitarena/__main__.py +3 -0
- commitarena-0.1.1/src/commitarena/agent.py +205 -0
- commitarena-0.1.1/src/commitarena/cli.py +313 -0
- commitarena-0.1.1/src/commitarena/demo/LICENSE-sqlparse +25 -0
- commitarena-0.1.1/src/commitarena/demo/results.jsonl +33 -0
- commitarena-0.1.1/src/commitarena/demo/run.json +36 -0
- commitarena-0.1.1/src/commitarena/demo/tasks.json +5603 -0
- commitarena-0.1.1/src/commitarena/errors.py +40 -0
- commitarena-0.1.1/src/commitarena/llm.py +206 -0
- commitarena-0.1.1/src/commitarena/mine.py +248 -0
- commitarena-0.1.1/src/commitarena/report.py +132 -0
- commitarena-0.1.1/src/commitarena/report_template.html +394 -0
- commitarena-0.1.1/src/commitarena/runner.py +298 -0
- commitarena-0.1.1/src/commitarena/sandbox.py +180 -0
- commitarena-0.1.1/src/commitarena/tasks.py +229 -0
- commitarena-0.1.1/src/commitarena/testrun.py +77 -0
- commitarena-0.1.1/tests/conftest.py +77 -0
- commitarena-0.1.1/tests/test_cli.py +74 -0
- commitarena-0.1.1/tests/test_core.py +282 -0
- commitarena-0.1.1/tests/test_docker.py +81 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.1 - 2026-11-03
|
|
4
|
+
|
|
5
|
+
Restore sqlparse license notice verbatim; fix leaderboard overflow.
|
|
6
|
+
|
|
7
|
+
- `src/commitarena/demo/LICENSE-sqlparse` is again a byte-for-byte copy of the upstream BSD-3-Clause license,
|
|
8
|
+
copyright notice included, as the license requires.
|
|
9
|
+
- Report: the leaderboard fits at 1280 px (the "Ended by" column wraps instead of pushing "Cutoff" out of the
|
|
10
|
+
card), and the page no longer overflows horizontally at 390 px; wide tables scroll inside their card.
|
|
11
|
+
|
|
12
|
+
## 0.1.0 - 2026-11-03
|
|
13
|
+
|
|
14
|
+
First release.
|
|
15
|
+
|
|
16
|
+
- `commitarena mine`: finds commits that change source and tests (Python + pytest), validates in Docker that
|
|
17
|
+
the new tests fail without the fix and pass with it (FAIL_TO_PASS) without breaking others (PASS_TO_PASS).
|
|
18
|
+
The task prompt is built from the failing tests only; the commit message is never used.
|
|
19
|
+
- `commitarena run`: one minimal agent loop with a single `bash` tool for every model, via one
|
|
20
|
+
OpenAI-compatible client (OpenRouter, OpenAI, Mistral, Ollama). Every command runs in a `--network none`
|
|
21
|
+
container with CPU, memory and time limits. Test files are restored before scoring. `--max-cost`
|
|
22
|
+
(default 1 USD) is checked before every call. Resumable run directories.
|
|
23
|
+
- `commitarena report`: static HTML report (EN/ES, light/dark, mobile): leaderboard, task x model matrix,
|
|
24
|
+
pass rate before vs after each model's training cutoff, model diff next to the human fix.
|
|
25
|
+
- `commitarena demo`: recorded real run of 11 sqlparse (BSD-3-Clause) fixes with Mistral Large 4, Ministral 8B
|
|
26
|
+
and Codestral, no keys or Docker needed.
|
|
27
|
+
- Agent loop details: older tool outputs are elided to fit a 16K window, exact repeated commands get a
|
|
28
|
+
notice, truncated outputs say how to read specific lines, commands with a null byte are a failed step,
|
|
29
|
+
empty or cut-off replies get up to two nudges.
|
|
30
|
+
- Python API (`run_task`, `load_tasks`, `ContextFile`, ...) with context-file injection for AGENTS.md /
|
|
31
|
+
CLAUDE.md experiments.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Diego Pérez
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: commitarena
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Your git history is the benchmark. Replay real bug fixes against any model, in a sandbox with no network.
|
|
5
|
+
Project-URL: Homepage, https://diegoperezg7.github.io/commitarena/
|
|
6
|
+
Project-URL: Source, https://github.com/diegoperezg7/commitarena
|
|
7
|
+
Project-URL: Issues, https://github.com/diegoperezg7/commitarena/issues
|
|
8
|
+
Author: Diego Pérez
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: agents,benchmark,docker,evaluation,git,llm,swe-bench
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Software Development :: Testing
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Requires-Dist: openai==3.42.1
|
|
22
|
+
Requires-Dist: rich==15.0.0
|
|
23
|
+
Requires-Dist: typer==0.27.3
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
<p align="center"><img src="docs/assets/banner.svg" alt="commitarena" width="640"></p>
|
|
27
|
+
|
|
28
|
+
<p align="center">
|
|
29
|
+
<a href="https://github.com/diegoperezg7/commitarena/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/diegoperezg7/commitarena/actions/workflows/ci.yml/badge.svg"></a>
|
|
30
|
+
<a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-3b5bd4"></a>
|
|
31
|
+
<a href="https://github.com/diegoperezg7/commitarena/releases"><img alt="Release" src="https://img.shields.io/github/v/release/diegoperezg7/commitarena?color=3b5bd4"></a>
|
|
32
|
+
<a href="https://github.com/diegoperezg7/commitarena/stargazers"><img alt="Stars" src="https://img.shields.io/github/stars/diegoperezg7/commitarena?color=3b5bd4"></a>
|
|
33
|
+
</p>
|
|
34
|
+
|
|
35
|
+
<p align="center"><b>Your git history is the benchmark. Replay real bug fixes against any model, in a sandbox with no network.</b></p>
|
|
36
|
+
|
|
37
|
+
<p align="center"><a href="README.es.md">Español</a> · <a href="https://diegoperezg7.github.io/commitarena/">Example report</a></p>
|
|
38
|
+
|
|
39
|
+
<p align="center"><img src="docs/assets/demo.gif" alt="commitarena demo in a terminal" width="760"></p>
|
|
40
|
+
|
|
41
|
+
commitarena mines commits from your repository where a bug fix came with a test, checks in Docker that the
|
|
42
|
+
test fails without the fix and passes with it, and then asks each model to make that test pass. Every
|
|
43
|
+
model gets the same small agent loop with one `bash` tool, and every command it runs executes in a
|
|
44
|
+
container started with `--network none`. The report splits the pass rate into fixes committed before and
|
|
45
|
+
after each model's training cutoff, so you can see whether a model solves the bug or remembers the patch.
|
|
46
|
+
|
|
47
|
+
## Why
|
|
48
|
+
|
|
49
|
+
There are good tools close to this. What I wanted and did not find in one place:
|
|
50
|
+
|
|
51
|
+
| | What it does | Difference |
|
|
52
|
+
|---|---|---|
|
|
53
|
+
| [sjarmak/codeprobe](https://github.com/sjarmak/codeprobe) (10 stars) | Mines merged PRs, runs agent CLIs, ranks with cost and an HTML report. | Its README says each agent runs "inside a `--network=bridge` container (the agent needs the model API)". In commitarena the model is called from the host and the code the model writes never has a network. |
|
|
54
|
+
| [PozziTiv4ik/Repo-Trials](https://github.com/PozziTiv4ik/Repo-Trials) (0 stars) | FAIL_TO_PASS tasks from your git history. | commitarena adds the same harness for every model, local ones included, and the before/after-cutoff split. |
|
|
55
|
+
| [harbor-framework/harbor](https://github.com/harbor-framework/harbor) (6,755 stars) | A general framework for agent evaluations. | commitarena is one command for one question: which model fixes the bugs of this repo. |
|
|
56
|
+
|
|
57
|
+
Star counts from the GitHub API on 2026-11-03.
|
|
58
|
+
|
|
59
|
+
Three things commitarena does on purpose:
|
|
60
|
+
|
|
61
|
+
1. **No network for model-written code.** The agent loop runs on your machine and only sends chat
|
|
62
|
+
requests. Each `bash` call goes through `docker exec` into a container with `--network none`,
|
|
63
|
+
`--cap-drop ALL`, `no-new-privileges`, 2 CPU, 2 GB, a PID limit and a per-command timeout.
|
|
64
|
+
2. **One harness for every model.** Same system prompt, same single tool, same step and time limits,
|
|
65
|
+
whether it is a hosted model or a 4B model on Ollama. No vendor agent, no extra tools.
|
|
66
|
+
3. **Solve or remember.** Public repos are in training data. The report shows pass rate on fixes dated
|
|
67
|
+
before each model's cutoff next to fixes dated after it. Cutoffs are configurable; by default the
|
|
68
|
+
model's release date is used, which is a safe upper bound.
|
|
69
|
+
|
|
70
|
+
## Quickstart
|
|
71
|
+
|
|
72
|
+
The demo needs no API keys and no Docker. It prints a recorded run and writes the HTML report.
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
uvx --from git+https://github.com/diegoperezg7/commitarena@v0.1.1 commitarena demo
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Or from a clone:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
git clone https://github.com/diegoperezg7/commitarena && cd commitarena && uv run commitarena demo
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
`uvx commitarena` is coming to PyPI.
|
|
85
|
+
|
|
86
|
+
## Example output
|
|
87
|
+
|
|
88
|
+
<!-- demo:start -->
|
|
89
|
+
```text
|
|
90
|
+
$ commitarena demo
|
|
91
|
+
Recorded result (not a live run): 2026-11-03, commitarena 0.1.0, models mistral/codestral-latest,
|
|
92
|
+
mistral/ministral-8b-latest, mistral/mistral-large-4, on Darwin arm64 (Apple M4, 16 GB RAM).
|
|
93
|
+
Repo: https://github.com/andialbrecht/sqlparse (BSD-3-Clause)
|
|
94
|
+
Leaderboard
|
|
95
|
+
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━┓
|
|
96
|
+
┃ model ┃ pass ┃ rate ┃ before cutoff ┃ after cutoff ┃ cost $ ┃ tokens ┃ avg s ┃ avg steps ┃
|
|
97
|
+
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━┩
|
|
98
|
+
│ mistral/mistral-large-4 │ 11/11 │ 100% │ 8/8 │ 3/3 │ 0.5401 │ 672,848 │ 118 │ 11.1 │
|
|
99
|
+
│ mistral/ministral-8b-latest │ 1/11 │ 9% │ 0/5 │ 1/6 │ 0.2445 │ 1,630,017 │ 68 │ 28.3 │
|
|
100
|
+
│ mistral/codestral-latest │ 0/11 │ 0% │ 0/4 │ 0/7 │ 0.6507 │ 2,038,536 │ 75 │ 27.8 │
|
|
101
|
+
└─────────────────────────────┴───────┴──────┴───────────────┴──────────────┴────────┴───────────┴───────┴───────────┘
|
|
102
|
+
```
|
|
103
|
+
<!-- demo:end -->
|
|
104
|
+
|
|
105
|
+
<p align="center"><a href="https://diegoperezg7.github.io/commitarena/"><img src="docs/assets/report-light.png" alt="report" width="760"></a></p>
|
|
106
|
+
|
|
107
|
+
How to read it: with the same prompt, tool, limits and sandbox, Mistral Large 4 fixed all 11 bugs,
|
|
108
|
+
including the 3 committed after its release (October 2026), so it was solving, not recalling. Ministral 8B
|
|
109
|
+
fixed one, and that one is dated after its own cutoff. Codestral fixed none. Three tasks after a cutoff is
|
|
110
|
+
a small sample: treat the split as a signal, not a verdict.
|
|
111
|
+
|
|
112
|
+
**Why Codestral scores 0/11.** It is the model, not the scoring: it repeated an earlier command verbatim
|
|
113
|
+
in 170 of its 304 tool calls, kept doing so after 163 "you already ran this exact command" notices from
|
|
114
|
+
the harness, ran out of its 30 steps in 9 of 11 attempts, left the code untouched in 6, and never edited a
|
|
115
|
+
test file. This is the start of the `PRIMARY KEY` task, whose human fix is one regex line in
|
|
116
|
+
`sqlparse/keywords.py` (full trajectories are in [docs/demo-run/trajectories](docs/demo-run/trajectories)):
|
|
117
|
+
|
|
118
|
+
```text
|
|
119
|
+
12 grep -n 'PRIMARY' sqlparse/keywords.py
|
|
120
|
+
13 sed -n '440,450p' sqlparse/keywords.py
|
|
121
|
+
14 sed -n '440,450p' sqlparse/keywords.py <- repeat notice
|
|
122
|
+
15 grep -n 'KEY' sqlparse/keywords.py
|
|
123
|
+
...
|
|
124
|
+
23 grep -n 'PRIMARY' sqlparse/keywords.py <- repeat notice
|
|
125
|
+
24 sed -n '440,450p' sqlparse/keywords.py <- repeat notice
|
|
126
|
+
25 grep -n 'KEY' sqlparse/keywords.py <- repeat notice
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Use it on your repo
|
|
130
|
+
|
|
131
|
+
You need Docker running, plus Ollama or an API key.
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# 1. Mine tasks: commits that change source and tests, validated in Docker
|
|
135
|
+
commitarena mine https://github.com/you/yourrepo --max-tasks 10
|
|
136
|
+
|
|
137
|
+
# 2. Run models (a local one and a hosted one)
|
|
138
|
+
export MISTRAL_API_KEY=...
|
|
139
|
+
commitarena run --tasks tasks/you-yourrepo/tasks.json \
|
|
140
|
+
--models ollama/qwen3:4b-16k,mistral/codestral-latest --max-cost 1
|
|
141
|
+
|
|
142
|
+
# 3. The report is written to runs/<timestamp>/report.html; re-render it with other cutoffs
|
|
143
|
+
commitarena report runs/<timestamp> --cutoff mistral/codestral-latest=2025-07-31 --open
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## How it works
|
|
147
|
+
|
|
148
|
+
```mermaid
|
|
149
|
+
flowchart LR
|
|
150
|
+
subgraph host[Your machine]
|
|
151
|
+
G[git history] --> M[mine: commits touching src + tests]
|
|
152
|
+
M --> V{Docker, no network:<br/>new tests fail before,<br/>pass after?}
|
|
153
|
+
V -->|yes| T[tasks.json<br/>failing tests + test diff<br/>no commit message]
|
|
154
|
+
T --> L[agent loop<br/>one bash tool]
|
|
155
|
+
L <-->|chat API| P[(model provider<br/>or Ollama)]
|
|
156
|
+
end
|
|
157
|
+
L -->|docker exec| S[sandbox<br/>--network none<br/>2 CPU, 2 GB]
|
|
158
|
+
S --> R[copy out the workspace]
|
|
159
|
+
R --> X[keep non-test changes only,<br/>restore original tests]
|
|
160
|
+
X --> Y[fresh no-network container:<br/>full test suite]
|
|
161
|
+
Y --> Z[report.html<br/>leaderboard, matrix,<br/>cutoff split, diffs]
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
- **Mining.** Non-merge commits that change at least one test file and at least one `.py` source file
|
|
165
|
+
(small fixes only by default). For each one the test suite runs twice in a no-network container: the
|
|
166
|
+
parent commit plus the new test files, and the fix commit. A task is kept when some tests go from
|
|
167
|
+
failing to passing (FAIL_TO_PASS) and nothing that passed before breaks (PASS_TO_PASS). The test image
|
|
168
|
+
is built once per repo with your install command, which is the only step with network.
|
|
169
|
+
- **The prompt** lists the failing tests, the test diff and the current failure output. The commit
|
|
170
|
+
message, the issue and the human fix are never shown. The workspace gets a fresh one-commit git history
|
|
171
|
+
so the real history cannot leak the fix.
|
|
172
|
+
- **Scoring.** After the attempt the workspace is copied out. Only changes to non-test files are applied
|
|
173
|
+
onto a pristine copy, so edits to tests or `conftest.py` are discarded, and the full suite runs in a
|
|
174
|
+
fresh container. Pass means every FAIL_TO_PASS test passes and no PASS_TO_PASS test fails.
|
|
175
|
+
- **Metrics.** Pass, cost (provider-reported for OpenRouter, otherwise tokens times list price; local
|
|
176
|
+
models cost 0), input and output tokens, wall time and steps (model calls).
|
|
177
|
+
|
|
178
|
+
## Configuration
|
|
179
|
+
|
|
180
|
+
| Flag | Default | |
|
|
181
|
+
|---|---|---|
|
|
182
|
+
| `run --models` | | Comma-separated `provider/model`. Providers: `openrouter`, `openai`, `mistral`, `ollama`. |
|
|
183
|
+
| `run --max-cost` | `1.0` | USD. Checked before every model call; the run stops with partial results. |
|
|
184
|
+
| `run --max-steps` / `--max-time` | `30` / `1200` | Model calls and seconds per attempt. |
|
|
185
|
+
| `run --cutoff MODEL=DATE` | release date | Training cutoff used for the before/after split (repeatable). |
|
|
186
|
+
| `run --price MODEL=IN,OUT` | built-in | USD per million tokens for models without a known price. |
|
|
187
|
+
| `run --context-file F` | | Inject an AGENTS.md / CLAUDE.md: `--context-mode both\|repo\|prompt`. |
|
|
188
|
+
| `run --strip-context-files` | off | Remove the repo's own AGENTS.md / CLAUDE.md before the attempt. |
|
|
189
|
+
| `run --cpus` / `--memory` / `--command-timeout` | `2` / `2g` / `120` | Sandbox limits. |
|
|
190
|
+
| `mine --since` / `--until` / `--scan` / `--max-tasks` | | Which commits to consider. |
|
|
191
|
+
| `mine --python` / `--setup` | `3.12` / `pip install -e .` | How the test image is built. |
|
|
192
|
+
|
|
193
|
+
Environment variables: `OPENROUTER_API_KEY`, `OPENAI_API_KEY`, `MISTRAL_API_KEY`, `OLLAMA_HOST`,
|
|
194
|
+
`COMMITARENA_CACHE` (clones, default `~/.cache/commitarena`). See [.env.example](.env.example). There is
|
|
195
|
+
no telemetry.
|
|
196
|
+
|
|
197
|
+
**Ollama context window.** Ollama's OpenAI-compatible endpoint ignores `num_ctx`, and its default
|
|
198
|
+
window can be 4096 tokens, which silently drops the task text and gives worse results. commitarena warns
|
|
199
|
+
about it. Use a variant with `num_ctx 16384` (the one used in development is `qwen3:4b-16k`); the agent
|
|
200
|
+
loop elides older tool outputs to stay inside 16K.
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
printf 'FROM qwen3:4b\nPARAMETER num_ctx 16384\n' > Modelfile && ollama create qwen3:4b-16k -f Modelfile
|
|
204
|
+
commitarena run --tasks tasks.json --models ollama/qwen3:4b-16k
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Local models go through exactly the same code path (qwen3:4b-16k was run during development), but it is not
|
|
208
|
+
in the recorded demo. On this machine it spent every 4096-token reply reasoning and never called the
|
|
209
|
+
tool, and its thinking could not be turned off through the OpenAI endpoint (`think: false`,
|
|
210
|
+
`reasoning_effort: "none"` and `/no_think` were all tried). Raising the reply limit for one model would
|
|
211
|
+
break the same-harness rule, so it was left out rather than shown with a misleading 0.
|
|
212
|
+
|
|
213
|
+
## Python API
|
|
214
|
+
|
|
215
|
+
```python
|
|
216
|
+
from commitarena import load_tasks, run_task, Budget, ContextFile
|
|
217
|
+
|
|
218
|
+
task = load_tasks("tasks.json")[0]
|
|
219
|
+
res = run_task(task, "ollama/qwen3:4b-16k", budget=Budget(max_cost=1.0),
|
|
220
|
+
context=ContextFile(open("AGENTS.md").read(), in_repo=True, in_prompt=True))
|
|
221
|
+
print(res.passed, res.cost_usd, res.tokens_in, res.steps, res.wall_time_s)
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Demo data
|
|
225
|
+
|
|
226
|
+
The recorded demo uses 11 tasks mined from [sqlparse](https://github.com/andialbrecht/sqlparse)
|
|
227
|
+
(BSD-3-Clause, Copyright (c) 2016, Andi Albrecht). The bundled files contain the failing tests, the test
|
|
228
|
+
diffs and the upstream fixes as diffs, each linked to its commit. The upstream license is bundled verbatim in
|
|
229
|
+
[src/commitarena/demo/LICENSE-sqlparse](src/commitarena/demo/LICENSE-sqlparse).
|
|
230
|
+
|
|
231
|
+
## Roadmap
|
|
232
|
+
|
|
233
|
+
- Other languages and test runners
|
|
234
|
+
- Claude Code and Codex as contestants
|
|
235
|
+
- GitHub issue text as an optional prompt
|
|
236
|
+
- pass@k and repeated attempts
|
|
237
|
+
- Parallel runs
|
|
238
|
+
- Export to Harbor
|
|
239
|
+
|
|
240
|
+
## License
|
|
241
|
+
|
|
242
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
<p align="center"><img src="docs/assets/banner.svg" alt="commitarena" width="640"></p>
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<a href="https://github.com/diegoperezg7/commitarena/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/diegoperezg7/commitarena/actions/workflows/ci.yml/badge.svg"></a>
|
|
5
|
+
<a href="LICENSE"><img alt="Licencia: MIT" src="https://img.shields.io/badge/license-MIT-3b5bd4"></a>
|
|
6
|
+
<a href="https://github.com/diegoperezg7/commitarena/releases"><img alt="Release" src="https://img.shields.io/github/v/release/diegoperezg7/commitarena?color=3b5bd4"></a>
|
|
7
|
+
<a href="https://github.com/diegoperezg7/commitarena/stargazers"><img alt="Estrellas" src="https://img.shields.io/github/stars/diegoperezg7/commitarena?color=3b5bd4"></a>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
<p align="center"><b>Tu historial de git es el benchmark. Reproduce fixes reales contra cualquier modelo, en un sandbox sin red.</b></p>
|
|
11
|
+
|
|
12
|
+
<p align="center"><a href="README.md">English</a> · <a href="https://diegoperezg7.github.io/commitarena/">Informe de ejemplo</a></p>
|
|
13
|
+
|
|
14
|
+
<p align="center"><img src="docs/assets/demo.gif" alt="demo de commitarena en una terminal" width="760"></p>
|
|
15
|
+
|
|
16
|
+
commitarena busca en tu repositorio los commits en los que un fix vino con un test, comprueba en Docker
|
|
17
|
+
que el test falla sin el fix y pasa con él, y le pide a cada modelo que haga pasar ese test. Todos los
|
|
18
|
+
modelos usan el mismo bucle de agente pequeño con una sola herramienta `bash`, y cada comando que ejecutan
|
|
19
|
+
corre en un contenedor arrancado con `--network none`. El informe separa el acierto en fixes anteriores y
|
|
20
|
+
posteriores a la fecha de corte de entrenamiento de cada modelo, para ver si el modelo resuelve el bug o
|
|
21
|
+
recuerda el parche.
|
|
22
|
+
|
|
23
|
+
## Por qué
|
|
24
|
+
|
|
25
|
+
Hay herramientas buenas cerca de esto. Lo que yo quería y no encontré junto:
|
|
26
|
+
|
|
27
|
+
| | Qué hace | Diferencia |
|
|
28
|
+
|---|---|---|
|
|
29
|
+
| [sjarmak/codeprobe](https://github.com/sjarmak/codeprobe) (10 estrellas) | Mina PRs fusionadas, corre CLIs de agentes y saca ranking con coste e informe HTML. | Su README dice que cada agente corre "inside a `--network=bridge` container (the agent needs the model API)". En commitarena el modelo se llama desde el host y el código que escribe el modelo nunca tiene red. |
|
|
30
|
+
| [PozziTiv4ik/Repo-Trials](https://github.com/PozziTiv4ik/Repo-Trials) (0 estrellas) | Tareas FAIL_TO_PASS a partir de tu historial de git. | commitarena añade el mismo arnés para todos los modelos, también los locales, y el corte antes/después de la fecha de entrenamiento. |
|
|
31
|
+
| [harbor-framework/harbor](https://github.com/harbor-framework/harbor) (6.755 estrellas) | Un framework general de evaluación de agentes. | commitarena es un comando para una pregunta: qué modelo arregla los bugs de este repo. |
|
|
32
|
+
|
|
33
|
+
Estrellas sacadas de la API de GitHub el 3 nov 2026.
|
|
34
|
+
|
|
35
|
+
Tres cosas que commitarena hace a propósito:
|
|
36
|
+
|
|
37
|
+
1. **Sin red para el código del modelo.** El bucle del agente corre en tu máquina y solo envía peticiones
|
|
38
|
+
de chat. Cada llamada a `bash` va por `docker exec` a un contenedor con `--network none`,
|
|
39
|
+
`--cap-drop ALL`, `no-new-privileges`, 2 CPU, 2 GB, límite de procesos y timeout por comando.
|
|
40
|
+
2. **Un arnés para todos.** Mismo prompt de sistema, misma herramienta, mismos límites de pasos y tiempo,
|
|
41
|
+
sea un modelo en la nube o uno de 4B en Ollama. Sin agentes del fabricante ni herramientas extra.
|
|
42
|
+
3. **¿Lo resuelve o lo recuerda?** Los repos públicos están en los datos de entrenamiento. El informe
|
|
43
|
+
pone el acierto en fixes anteriores a la fecha de corte de cada modelo junto al de los posteriores. Las
|
|
44
|
+
fechas se configuran; por defecto se usa la fecha de lanzamiento del modelo, que es una cota segura.
|
|
45
|
+
|
|
46
|
+
## Inicio rápido
|
|
47
|
+
|
|
48
|
+
La demo no necesita claves ni Docker. Muestra una ejecución grabada y escribe el informe HTML.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
uvx --from git+https://github.com/diegoperezg7/commitarena@v0.1.1 commitarena demo
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
O desde un clon:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
git clone https://github.com/diegoperezg7/commitarena && cd commitarena && uv run commitarena demo
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`uvx commitarena` llegará pronto a PyPI.
|
|
61
|
+
|
|
62
|
+
## Ejemplo de salida
|
|
63
|
+
|
|
64
|
+
<!-- demo:start -->
|
|
65
|
+
```text
|
|
66
|
+
$ commitarena demo
|
|
67
|
+
Recorded result (not a live run): 2026-11-03, commitarena 0.1.0, models mistral/codestral-latest,
|
|
68
|
+
mistral/ministral-8b-latest, mistral/mistral-large-4, on Darwin arm64 (Apple M4, 16 GB RAM).
|
|
69
|
+
Repo: https://github.com/andialbrecht/sqlparse (BSD-3-Clause)
|
|
70
|
+
Leaderboard
|
|
71
|
+
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━┓
|
|
72
|
+
┃ model ┃ pass ┃ rate ┃ before cutoff ┃ after cutoff ┃ cost $ ┃ tokens ┃ avg s ┃ avg steps ┃
|
|
73
|
+
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━┩
|
|
74
|
+
│ mistral/mistral-large-4 │ 11/11 │ 100% │ 8/8 │ 3/3 │ 0.5401 │ 672,848 │ 118 │ 11.1 │
|
|
75
|
+
│ mistral/ministral-8b-latest │ 1/11 │ 9% │ 0/5 │ 1/6 │ 0.2445 │ 1,630,017 │ 68 │ 28.3 │
|
|
76
|
+
│ mistral/codestral-latest │ 0/11 │ 0% │ 0/4 │ 0/7 │ 0.6507 │ 2,038,536 │ 75 │ 27.8 │
|
|
77
|
+
└─────────────────────────────┴───────┴──────┴───────────────┴──────────────┴────────┴───────────┴───────┴───────────┘
|
|
78
|
+
```
|
|
79
|
+
<!-- demo:end -->
|
|
80
|
+
|
|
81
|
+
<p align="center"><a href="https://diegoperezg7.github.io/commitarena/"><img src="docs/assets/report-dark.png" alt="report" width="760"></a></p>
|
|
82
|
+
|
|
83
|
+
Cómo leerlo: con el mismo prompt, herramienta, límites y sandbox, Mistral Large 4 arregló los 11 bugs,
|
|
84
|
+
incluidos los 3 posteriores a su lanzamiento (octubre de 2026), así que los resolvió, no los recordó.
|
|
85
|
+
Ministral 8B arregló uno, y ese es posterior a su propio corte. Codestral no arregló ninguno. Tres tareas
|
|
86
|
+
después del corte es una muestra pequeña: es una señal, no un veredicto.
|
|
87
|
+
|
|
88
|
+
**Por qué Codestral saca 0/11.** Es el modelo, no la puntuación: repitió literalmente un comando anterior
|
|
89
|
+
en 170 de sus 304 llamadas, siguió haciéndolo tras 163 avisos del arnés ("you already ran this exact
|
|
90
|
+
command"), agotó sus 30 pasos en 9 de 11 intentos, no cambió el código en 6 y no tocó ningún test. Así
|
|
91
|
+
empieza la tarea de `PRIMARY KEY`, cuyo fix humano es una línea de regex en `sqlparse/keywords.py`
|
|
92
|
+
(trayectorias completas en [docs/demo-run/trajectories](docs/demo-run/trajectories)):
|
|
93
|
+
|
|
94
|
+
```text
|
|
95
|
+
12 grep -n 'PRIMARY' sqlparse/keywords.py
|
|
96
|
+
13 sed -n '440,450p' sqlparse/keywords.py
|
|
97
|
+
14 sed -n '440,450p' sqlparse/keywords.py <- aviso de repetición
|
|
98
|
+
15 grep -n 'KEY' sqlparse/keywords.py
|
|
99
|
+
...
|
|
100
|
+
23 grep -n 'PRIMARY' sqlparse/keywords.py <- aviso de repetición
|
|
101
|
+
24 sed -n '440,450p' sqlparse/keywords.py <- aviso de repetición
|
|
102
|
+
25 grep -n 'KEY' sqlparse/keywords.py <- aviso de repetición
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Úsalo en tu repo
|
|
106
|
+
|
|
107
|
+
Necesitas Docker en marcha y Ollama o una API key.
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
# 1. Minar tareas: commits que cambian código y tests, validados en Docker
|
|
111
|
+
commitarena mine https://github.com/tu/turepo --max-tasks 10
|
|
112
|
+
|
|
113
|
+
# 2. Ejecutar modelos (uno local y uno en la nube)
|
|
114
|
+
export MISTRAL_API_KEY=...
|
|
115
|
+
commitarena run --tasks tasks/tu-turepo/tasks.json \
|
|
116
|
+
--models ollama/qwen3:4b-16k,mistral/codestral-latest --max-cost 1
|
|
117
|
+
|
|
118
|
+
# 3. El informe queda en runs/<fecha>/report.html; se puede regenerar con otras fechas de corte
|
|
119
|
+
commitarena report runs/<fecha> --cutoff mistral/codestral-latest=2025-07-31 --open
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Cómo funciona
|
|
123
|
+
|
|
124
|
+
```mermaid
|
|
125
|
+
flowchart LR
|
|
126
|
+
subgraph host[Tu máquina]
|
|
127
|
+
G[historial de git] --> M[mine: commits que tocan src + tests]
|
|
128
|
+
M --> V{Docker sin red:<br/>¿los tests nuevos fallan antes<br/>y pasan después?}
|
|
129
|
+
V -->|sí| T[tasks.json<br/>tests que fallan + diff de tests<br/>sin mensaje de commit]
|
|
130
|
+
T --> L[bucle de agente<br/>una herramienta bash]
|
|
131
|
+
L <-->|API de chat| P[(proveedor del modelo<br/>u Ollama)]
|
|
132
|
+
end
|
|
133
|
+
L -->|docker exec| S[sandbox<br/>--network none<br/>2 CPU, 2 GB]
|
|
134
|
+
S --> R[se copia el workspace]
|
|
135
|
+
R --> X[solo cambios fuera de tests,<br/>tests originales restaurados]
|
|
136
|
+
X --> Y[contenedor nuevo sin red:<br/>suite completa]
|
|
137
|
+
Y --> Z[report.html<br/>ranking, matriz,<br/>corte por fecha, diffs]
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
- **Minado.** Commits sin merge que cambian al menos un fichero de test y al menos un `.py` de código
|
|
141
|
+
(por defecto solo fixes pequeños). Para cada uno la suite corre dos veces en un contenedor sin red: el
|
|
142
|
+
commit padre con los tests nuevos, y el commit del fix. La tarea se queda si algún test pasa de fallar a
|
|
143
|
+
pasar (FAIL_TO_PASS) y no se rompe nada de lo que pasaba (PASS_TO_PASS). La imagen de tests se construye
|
|
144
|
+
una vez por repo con tu comando de instalación, que es el único paso con red.
|
|
145
|
+
- **El prompt** lista los tests que fallan, el diff de los tests y la salida del fallo. Nunca se enseña
|
|
146
|
+
el mensaje del commit, la issue ni el fix humano. El workspace lleva un historial de git nuevo de un solo
|
|
147
|
+
commit, para que el historial real no filtre el fix.
|
|
148
|
+
- **Puntuación.** Al acabar se copia el workspace. Solo se aplican los cambios en ficheros que no son de
|
|
149
|
+
test sobre una copia limpia, así que lo que toque en tests o `conftest.py` se descarta, y la suite
|
|
150
|
+
completa corre en un contenedor nuevo. Acierto = pasan todos los FAIL_TO_PASS y no falla ningún
|
|
151
|
+
PASS_TO_PASS.
|
|
152
|
+
- **Métricas.** Acierto, coste (el que informa OpenRouter, si no tokens por precio de lista; los modelos
|
|
153
|
+
locales cuestan 0), tokens de entrada y salida, tiempo y pasos (llamadas al modelo).
|
|
154
|
+
|
|
155
|
+
## Configuración
|
|
156
|
+
|
|
157
|
+
| Opción | Por defecto | |
|
|
158
|
+
|---|---|---|
|
|
159
|
+
| `run --models` | | `proveedor/modelo` separados por comas. Proveedores: `openrouter`, `openai`, `mistral`, `ollama`. |
|
|
160
|
+
| `run --max-cost` | `1.0` | USD. Se comprueba antes de cada llamada; la ejecución para con resultados parciales. |
|
|
161
|
+
| `run --max-steps` / `--max-time` | `30` / `1200` | Llamadas al modelo y segundos por intento. |
|
|
162
|
+
| `run --cutoff MODELO=FECHA` | fecha de lanzamiento | Fecha de corte para el reparto antes/después (repetible). |
|
|
163
|
+
| `run --price MODELO=IN,OUT` | integrado | USD por millón de tokens para modelos sin precio conocido. |
|
|
164
|
+
| `run --context-file F` | | Inyecta un AGENTS.md / CLAUDE.md: `--context-mode both\|repo\|prompt`. |
|
|
165
|
+
| `run --strip-context-files` | no | Quita el AGENTS.md / CLAUDE.md propio del repo antes del intento. |
|
|
166
|
+
| `run --cpus` / `--memory` / `--command-timeout` | `2` / `2g` / `120` | Límites del sandbox. |
|
|
167
|
+
| `mine --since` / `--until` / `--scan` / `--max-tasks` | | Qué commits se miran. |
|
|
168
|
+
| `mine --python` / `--setup` | `3.12` / `pip install -e .` | Cómo se construye la imagen de tests. |
|
|
169
|
+
|
|
170
|
+
Variables de entorno: `OPENROUTER_API_KEY`, `OPENAI_API_KEY`, `MISTRAL_API_KEY`, `OLLAMA_HOST`,
|
|
171
|
+
`COMMITARENA_CACHE` (clones, por defecto `~/.cache/commitarena`). Ver [.env.example](.env.example). No hay
|
|
172
|
+
telemetría.
|
|
173
|
+
|
|
174
|
+
**Ventana de contexto en Ollama.** El endpoint compatible con OpenAI de Ollama ignora `num_ctx`, y la
|
|
175
|
+
ventana por defecto puede ser de 4096 tokens, lo que tira el texto de la tarea sin avisar y da peores
|
|
176
|
+
resultados. commitarena avisa. Usa una variante con `num_ctx 16384` (la usada en el desarrollo es
|
|
177
|
+
`qwen3:4b-16k`); el bucle del agente elide las salidas más antiguas para caber en 16K.
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
printf 'FROM qwen3:4b\nPARAMETER num_ctx 16384\n' > Modelfile && ollama create qwen3:4b-16k -f Modelfile
|
|
181
|
+
commitarena run --tasks tasks.json --models ollama/qwen3:4b-16k
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Los modelos locales pasan exactamente por el mismo código (qwen3:4b-16k se ejecutó durante el desarrollo),
|
|
185
|
+
pero no está en la demo grabada. En esta máquina gastaba los 4096 tokens de cada respuesta
|
|
186
|
+
razonando y nunca llamaba a la herramienta, y no hubo forma de desactivar el razonamiento por el endpoint
|
|
187
|
+
de OpenAI (se probaron `think: false`, `reasoning_effort: "none"` y `/no_think`). Subir el límite solo para
|
|
188
|
+
un modelo rompería la regla de arnés único, así que se dejó fuera en vez de mostrar un 0 engañoso.
|
|
189
|
+
|
|
190
|
+
## API de Python
|
|
191
|
+
|
|
192
|
+
```python
|
|
193
|
+
from commitarena import load_tasks, run_task, Budget, ContextFile
|
|
194
|
+
|
|
195
|
+
task = load_tasks("tasks.json")[0]
|
|
196
|
+
res = run_task(task, "ollama/qwen3:4b-16k", budget=Budget(max_cost=1.0),
|
|
197
|
+
context=ContextFile(open("AGENTS.md").read(), in_repo=True, in_prompt=True))
|
|
198
|
+
print(res.passed, res.cost_usd, res.tokens_in, res.steps, res.wall_time_s)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Datos de la demo
|
|
202
|
+
|
|
203
|
+
La demo grabada usa 11 tareas minadas de [sqlparse](https://github.com/andialbrecht/sqlparse)
|
|
204
|
+
(BSD-3-Clause, Copyright (c) 2016, Andi Albrecht). Los ficheros incluidos contienen los tests que fallan,
|
|
205
|
+
los diffs de los tests y los fixes originales como diffs, cada uno enlazado a su commit. La licencia original va incluida literal en
|
|
206
|
+
[src/commitarena/demo/LICENSE-sqlparse](src/commitarena/demo/LICENSE-sqlparse).
|
|
207
|
+
|
|
208
|
+
## Hoja de ruta
|
|
209
|
+
|
|
210
|
+
- Otros lenguajes y runners de tests
|
|
211
|
+
- Claude Code y Codex como concursantes
|
|
212
|
+
- Texto de la issue de GitHub como prompt opcional
|
|
213
|
+
- pass@k e intentos repetidos
|
|
214
|
+
- Ejecución en paralelo
|
|
215
|
+
- Exportar a Harbor
|
|
216
|
+
|
|
217
|
+
## Licencia
|
|
218
|
+
|
|
219
|
+
MIT. Ver [LICENSE](LICENSE).
|