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.
@@ -0,0 +1,15 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ dist/
5
+ build/
6
+ *.egg-info/
7
+ .pytest_cache/
8
+ .ruff_cache/
9
+ .env
10
+ .env.*
11
+ !.env.example
12
+ runs/
13
+ tasks/
14
+ commitarena-demo.html
15
+ .DS_Store
@@ -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).