bugbout 0.1.0__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.
- bugbout-0.1.0/.gitignore +27 -0
- bugbout-0.1.0/CHANGELOG.md +15 -0
- bugbout-0.1.0/LICENSE +21 -0
- bugbout-0.1.0/PKG-INFO +120 -0
- bugbout-0.1.0/README.md +88 -0
- bugbout-0.1.0/docs/agents.md +162 -0
- bugbout-0.1.0/docs/configuration.md +113 -0
- bugbout-0.1.0/docs/how-it-works.md +108 -0
- bugbout-0.1.0/pyproject.toml +89 -0
- bugbout-0.1.0/src/bugbout/__about__.py +1 -0
- bugbout-0.1.0/src/bugbout/__init__.py +60 -0
- bugbout-0.1.0/src/bugbout/__main__.py +5 -0
- bugbout-0.1.0/src/bugbout/agents/__init__.py +26 -0
- bugbout-0.1.0/src/bugbout/agents/base.py +287 -0
- bugbout-0.1.0/src/bugbout/agents/claude_code.py +107 -0
- bugbout-0.1.0/src/bugbout/agents/codex.py +105 -0
- bugbout-0.1.0/src/bugbout/agents/command.py +83 -0
- bugbout-0.1.0/src/bugbout/agents/gemini_cli.py +73 -0
- bugbout-0.1.0/src/bugbout/agents/mini_swe.py +103 -0
- bugbout-0.1.0/src/bugbout/agents/plugins/bugbout_mini_env.py +27 -0
- bugbout-0.1.0/src/bugbout/agents/registry.py +63 -0
- bugbout-0.1.0/src/bugbout/agents/vendors.py +36 -0
- bugbout-0.1.0/src/bugbout/arena/__init__.py +30 -0
- bugbout-0.1.0/src/bugbout/arena/briefs.py +176 -0
- bugbout-0.1.0/src/bugbout/arena/exhibits.py +78 -0
- bugbout-0.1.0/src/bugbout/arena/judge.py +301 -0
- bugbout-0.1.0/src/bugbout/arena/matrix.py +189 -0
- bugbout-0.1.0/src/bugbout/arena/race.py +266 -0
- bugbout-0.1.0/src/bugbout/bout.py +316 -0
- bugbout-0.1.0/src/bugbout/cli/__init__.py +5 -0
- bugbout-0.1.0/src/bugbout/cli/main.py +168 -0
- bugbout-0.1.0/src/bugbout/config.py +145 -0
- bugbout-0.1.0/src/bugbout/doctor.py +83 -0
- bugbout-0.1.0/src/bugbout/errors.py +39 -0
- bugbout-0.1.0/src/bugbout/home.py +22 -0
- bugbout-0.1.0/src/bugbout/jsonfile.py +34 -0
- bugbout-0.1.0/src/bugbout/log.py +30 -0
- bugbout-0.1.0/src/bugbout/naming.py +12 -0
- bugbout-0.1.0/src/bugbout/project.py +129 -0
- bugbout-0.1.0/src/bugbout/py.typed +0 -0
- bugbout-0.1.0/src/bugbout/report/__init__.py +19 -0
- bugbout-0.1.0/src/bugbout/report/build.py +218 -0
- bugbout-0.1.0/src/bugbout/report/markdown.py +161 -0
- bugbout-0.1.0/src/bugbout/report/model.py +162 -0
- bugbout-0.1.0/src/bugbout/report/terminal.py +42 -0
- bugbout-0.1.0/src/bugbout/report/text.py +38 -0
- bugbout-0.1.0/src/bugbout/sandbox/__init__.py +51 -0
- bugbout-0.1.0/src/bugbout/sandbox/base.py +60 -0
- bugbout-0.1.0/src/bugbout/sandbox/bubblewrap.py +80 -0
- bugbout-0.1.0/src/bugbout/sandbox/seatbelt.py +71 -0
- bugbout-0.1.0/src/bugbout/scaffold.py +135 -0
- bugbout-0.1.0/src/bugbout/store.py +125 -0
- bugbout-0.1.0/src/bugbout/tasks/__init__.py +18 -0
- bugbout-0.1.0/src/bugbout/tasks/issues.py +149 -0
- bugbout-0.1.0/src/bugbout/tasks/mining.py +205 -0
- bugbout-0.1.0/src/bugbout/tasks/oracle.py +187 -0
- bugbout-0.1.0/src/bugbout/tasks/task.py +60 -0
- bugbout-0.1.0/src/bugbout/workspace/__init__.py +8 -0
- bugbout-0.1.0/src/bugbout/workspace/environment.py +225 -0
- bugbout-0.1.0/src/bugbout/workspace/junit.py +29 -0
- bugbout-0.1.0/src/bugbout/workspace/patch.py +261 -0
- bugbout-0.1.0/src/bugbout/workspace/repository.py +139 -0
- bugbout-0.1.0/src/bugbout/workspace/workspace.py +85 -0
- bugbout-0.1.0/tests/__init__.py +0 -0
- bugbout-0.1.0/tests/agents/__init__.py +0 -0
- bugbout-0.1.0/tests/agents/test_adapters.py +212 -0
- bugbout-0.1.0/tests/agents/test_mini_env.py +41 -0
- bugbout-0.1.0/tests/agents/test_registry.py +52 -0
- bugbout-0.1.0/tests/agents/test_running.py +98 -0
- bugbout-0.1.0/tests/agents/test_vendors.py +24 -0
- bugbout-0.1.0/tests/arena/__init__.py +0 -0
- bugbout-0.1.0/tests/arena/test_judge.py +135 -0
- bugbout-0.1.0/tests/arena/test_matrix.py +99 -0
- bugbout-0.1.0/tests/arena/test_race.py +155 -0
- bugbout-0.1.0/tests/cli/__init__.py +0 -0
- bugbout-0.1.0/tests/cli/test_cli.py +116 -0
- bugbout-0.1.0/tests/conftest.py +25 -0
- bugbout-0.1.0/tests/processes.py +18 -0
- bugbout-0.1.0/tests/report/__init__.py +0 -0
- bugbout-0.1.0/tests/report/test_report.py +149 -0
- bugbout-0.1.0/tests/sandbox/__init__.py +0 -0
- bugbout-0.1.0/tests/sandbox/test_sandbox.py +128 -0
- bugbout-0.1.0/tests/tasks/__init__.py +0 -0
- bugbout-0.1.0/tests/tasks/test_issues.py +51 -0
- bugbout-0.1.0/tests/tasks/test_mining.py +177 -0
- bugbout-0.1.0/tests/tasks/test_oracle.py +81 -0
- bugbout-0.1.0/tests/test_bout.py +112 -0
- bugbout-0.1.0/tests/test_doctor.py +31 -0
- bugbout-0.1.0/tests/test_project.py +125 -0
- bugbout-0.1.0/tests/test_scaffold.py +74 -0
- bugbout-0.1.0/tests/test_store.py +63 -0
- bugbout-0.1.0/tests/toy.py +138 -0
- bugbout-0.1.0/tests/workspace/__init__.py +0 -0
- bugbout-0.1.0/tests/workspace/test_environment.py +123 -0
- bugbout-0.1.0/tests/workspace/test_junit.py +30 -0
- bugbout-0.1.0/tests/workspace/test_patch.py +97 -0
- bugbout-0.1.0/tests/workspace/test_repository.py +92 -0
bugbout-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
build/
|
|
6
|
+
dist/
|
|
7
|
+
.venv/
|
|
8
|
+
venv/
|
|
9
|
+
|
|
10
|
+
# Tooling
|
|
11
|
+
.pytest_cache/
|
|
12
|
+
.mypy_cache/
|
|
13
|
+
.ruff_cache/
|
|
14
|
+
.coverage
|
|
15
|
+
coverage.xml
|
|
16
|
+
htmlcov/
|
|
17
|
+
|
|
18
|
+
# bugbout's own results
|
|
19
|
+
.bugbout/
|
|
20
|
+
|
|
21
|
+
# Secrets
|
|
22
|
+
.env
|
|
23
|
+
.env.*
|
|
24
|
+
*.pem
|
|
25
|
+
|
|
26
|
+
# OS
|
|
27
|
+
.DS_Store
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 - 2026-10-20
|
|
4
|
+
|
|
5
|
+
First release.
|
|
6
|
+
|
|
7
|
+
- Mine tasks from a project's own fixed bugs, with ground truth from the maintainers'
|
|
8
|
+
tests.
|
|
9
|
+
- Race Codex, Claude Code, Gemini CLI, mini-swe-agent, or any agent with a command
|
|
10
|
+
line, in sandboxed, history-free checkouts.
|
|
11
|
+
- Cross-examine every patch with every agent's tests, and pick one per bug under a
|
|
12
|
+
judge policy.
|
|
13
|
+
- Report in the terminal, Markdown and JSON.
|
|
14
|
+
- `bugbout init`, `doctor`, `tasks`, `run` and `report`; and the same pipeline from
|
|
15
|
+
Python through `Bout`.
|
bugbout-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Keerthirajan58
|
|
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.
|
bugbout-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: bugbout
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Find out which coding agent actually fixes bugs in your codebase.
|
|
5
|
+
Project-URL: Homepage, https://github.com/Keerthirajan58/bugbout
|
|
6
|
+
Project-URL: Issues, https://github.com/Keerthirajan58/bugbout/issues
|
|
7
|
+
Author-email: Keerthirajan58 <keerthirajan19122001@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: benchmark,coding-agents,evaluation,llm,swe-bench,testing
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: MacOS
|
|
15
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
20
|
+
Classifier: Topic :: Software Development :: Testing
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.12
|
|
23
|
+
Requires-Dist: pydantic>=2.10
|
|
24
|
+
Requires-Dist: rich>=13.9
|
|
25
|
+
Requires-Dist: typer>=0.15
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: mypy==2.4.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest-cov>=6.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest>=8.3; extra == 'dev'
|
|
30
|
+
Requires-Dist: ruff==0.17.1; extra == 'dev'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# bugbout
|
|
34
|
+
|
|
35
|
+
**Which coding agent actually fixes bugs in *your* codebase?**
|
|
36
|
+
|
|
37
|
+
Public benchmarks tell you how coding agents do on someone else's code. bugbout tells
|
|
38
|
+
you how they do on yours. It replays real bugs from your project's own history, lets
|
|
39
|
+
agents race to fix them, and scores every patch with the tests your maintainers wrote
|
|
40
|
+
alongside the real fix - tests no agent ever gets to see.
|
|
41
|
+
|
|
42
|
+
## Why
|
|
43
|
+
|
|
44
|
+
- **Your code, not a leaderboard's.** An agent that tops a benchmark can still stumble
|
|
45
|
+
on your conventions, your framework and your test suite. Measure it where you will
|
|
46
|
+
use it.
|
|
47
|
+
- **Scored by your own tests.** Every task is a fix your team already shipped with a
|
|
48
|
+
new test, and that test decides whether an agent's patch really fixes the bug.
|
|
49
|
+
- **Bring any agent.** Codex, Claude Code, Gemini CLI and mini-swe-agent work out of
|
|
50
|
+
the box, and any other agent with a command line takes a few lines of config - so
|
|
51
|
+
you can also compare models, including local ones.
|
|
52
|
+
- **Cross-examination.** Agents' tests are run against each other's patches, so you
|
|
53
|
+
also learn whether an "agent jury" could pick, or gate, a patch on its own before you
|
|
54
|
+
trust one in your workflow.
|
|
55
|
+
- **Safe to run.** Agents work in history-free checkouts, inside an OS sandbox, with
|
|
56
|
+
web access switched off.
|
|
57
|
+
|
|
58
|
+
## Quickstart
|
|
59
|
+
|
|
60
|
+
You need Python 3.12+, git, [uv](https://docs.astral.sh/uv/), and at least one coding
|
|
61
|
+
agent CLI installed and logged in.
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install git+https://github.com/Keerthirajan58/bugbout
|
|
65
|
+
|
|
66
|
+
cd your-project
|
|
67
|
+
bugbout init # writes bugbout.toml from your layout and the agents you have
|
|
68
|
+
bugbout doctor # checks everything before any agent spends quota
|
|
69
|
+
bugbout run # mines tasks, races the agents, judges and scores
|
|
70
|
+
bugbout report --format markdown
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
A bout is resumable: stop it at any point and run it again to carry on. Add an agent
|
|
74
|
+
later and only that agent runs.
|
|
75
|
+
|
|
76
|
+
## How it works
|
|
77
|
+
|
|
78
|
+
1. **Mine.** Fixes in your git history that name an issue and add a test become tasks.
|
|
79
|
+
2. **Ground truth.** The maintainers' tests run before and after their fix; the tests
|
|
80
|
+
that flip from failing to passing define what "fixed" means.
|
|
81
|
+
3. **Race.** Each agent gets the issue and a checkout of the code before the fix - no
|
|
82
|
+
git history, none of the fix's tests - and works inside a sandbox.
|
|
83
|
+
4. **Cross-examine.** Every test the agents wrote runs against every patch.
|
|
84
|
+
5. **Judge and score.** A policy picks one patch per bug from the executed evidence,
|
|
85
|
+
then the hidden tests score every patch and every pick.
|
|
86
|
+
|
|
87
|
+
More in [How it works](docs/how-it-works.md).
|
|
88
|
+
|
|
89
|
+
## Configuration
|
|
90
|
+
|
|
91
|
+
`bugbout init` writes a commented `bugbout.toml`. A minimal one looks like this:
|
|
92
|
+
|
|
93
|
+
```toml
|
|
94
|
+
[project]
|
|
95
|
+
source = "src/mypkg"
|
|
96
|
+
tests = "tests"
|
|
97
|
+
|
|
98
|
+
[[contestants]]
|
|
99
|
+
agent = "codex"
|
|
100
|
+
|
|
101
|
+
[[contestants]]
|
|
102
|
+
agent = "claude-code"
|
|
103
|
+
model = "sonnet"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Every setting is described in [Configuration](docs/configuration.md); the built-in
|
|
107
|
+
agents, sandboxing and adding your own agent are covered in [Agents](docs/agents.md).
|
|
108
|
+
|
|
109
|
+
## From Python
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
from bugbout import Bout, render_markdown
|
|
113
|
+
|
|
114
|
+
report = Bout.load(".").run()
|
|
115
|
+
print(render_markdown(report))
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## License
|
|
119
|
+
|
|
120
|
+
[MIT](LICENSE)
|
bugbout-0.1.0/README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# bugbout
|
|
2
|
+
|
|
3
|
+
**Which coding agent actually fixes bugs in *your* codebase?**
|
|
4
|
+
|
|
5
|
+
Public benchmarks tell you how coding agents do on someone else's code. bugbout tells
|
|
6
|
+
you how they do on yours. It replays real bugs from your project's own history, lets
|
|
7
|
+
agents race to fix them, and scores every patch with the tests your maintainers wrote
|
|
8
|
+
alongside the real fix - tests no agent ever gets to see.
|
|
9
|
+
|
|
10
|
+
## Why
|
|
11
|
+
|
|
12
|
+
- **Your code, not a leaderboard's.** An agent that tops a benchmark can still stumble
|
|
13
|
+
on your conventions, your framework and your test suite. Measure it where you will
|
|
14
|
+
use it.
|
|
15
|
+
- **Scored by your own tests.** Every task is a fix your team already shipped with a
|
|
16
|
+
new test, and that test decides whether an agent's patch really fixes the bug.
|
|
17
|
+
- **Bring any agent.** Codex, Claude Code, Gemini CLI and mini-swe-agent work out of
|
|
18
|
+
the box, and any other agent with a command line takes a few lines of config - so
|
|
19
|
+
you can also compare models, including local ones.
|
|
20
|
+
- **Cross-examination.** Agents' tests are run against each other's patches, so you
|
|
21
|
+
also learn whether an "agent jury" could pick, or gate, a patch on its own before you
|
|
22
|
+
trust one in your workflow.
|
|
23
|
+
- **Safe to run.** Agents work in history-free checkouts, inside an OS sandbox, with
|
|
24
|
+
web access switched off.
|
|
25
|
+
|
|
26
|
+
## Quickstart
|
|
27
|
+
|
|
28
|
+
You need Python 3.12+, git, [uv](https://docs.astral.sh/uv/), and at least one coding
|
|
29
|
+
agent CLI installed and logged in.
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install git+https://github.com/Keerthirajan58/bugbout
|
|
33
|
+
|
|
34
|
+
cd your-project
|
|
35
|
+
bugbout init # writes bugbout.toml from your layout and the agents you have
|
|
36
|
+
bugbout doctor # checks everything before any agent spends quota
|
|
37
|
+
bugbout run # mines tasks, races the agents, judges and scores
|
|
38
|
+
bugbout report --format markdown
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
A bout is resumable: stop it at any point and run it again to carry on. Add an agent
|
|
42
|
+
later and only that agent runs.
|
|
43
|
+
|
|
44
|
+
## How it works
|
|
45
|
+
|
|
46
|
+
1. **Mine.** Fixes in your git history that name an issue and add a test become tasks.
|
|
47
|
+
2. **Ground truth.** The maintainers' tests run before and after their fix; the tests
|
|
48
|
+
that flip from failing to passing define what "fixed" means.
|
|
49
|
+
3. **Race.** Each agent gets the issue and a checkout of the code before the fix - no
|
|
50
|
+
git history, none of the fix's tests - and works inside a sandbox.
|
|
51
|
+
4. **Cross-examine.** Every test the agents wrote runs against every patch.
|
|
52
|
+
5. **Judge and score.** A policy picks one patch per bug from the executed evidence,
|
|
53
|
+
then the hidden tests score every patch and every pick.
|
|
54
|
+
|
|
55
|
+
More in [How it works](docs/how-it-works.md).
|
|
56
|
+
|
|
57
|
+
## Configuration
|
|
58
|
+
|
|
59
|
+
`bugbout init` writes a commented `bugbout.toml`. A minimal one looks like this:
|
|
60
|
+
|
|
61
|
+
```toml
|
|
62
|
+
[project]
|
|
63
|
+
source = "src/mypkg"
|
|
64
|
+
tests = "tests"
|
|
65
|
+
|
|
66
|
+
[[contestants]]
|
|
67
|
+
agent = "codex"
|
|
68
|
+
|
|
69
|
+
[[contestants]]
|
|
70
|
+
agent = "claude-code"
|
|
71
|
+
model = "sonnet"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Every setting is described in [Configuration](docs/configuration.md); the built-in
|
|
75
|
+
agents, sandboxing and adding your own agent are covered in [Agents](docs/agents.md).
|
|
76
|
+
|
|
77
|
+
## From Python
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from bugbout import Bout, render_markdown
|
|
81
|
+
|
|
82
|
+
report = Bout.load(".").run()
|
|
83
|
+
print(render_markdown(report))
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## License
|
|
87
|
+
|
|
88
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Agents
|
|
2
|
+
|
|
3
|
+
bugbout reimplements no agent. Each adapter runs the same command line a developer
|
|
4
|
+
would, headlessly, and judges the agent only by what it leaves on disk. Two rules hold
|
|
5
|
+
for every adapter:
|
|
6
|
+
|
|
7
|
+
- **Nothing personal leaks in.** Your own agent configuration - plugins, memories, MCP
|
|
8
|
+
servers, house rules - is left out wherever the agent allows it, so the comparison is
|
|
9
|
+
between agents, not set-ups.
|
|
10
|
+
- **Nothing from the future leaks in.** The tasks are real bugs with public fixes, so web
|
|
11
|
+
tools are off, commands run in a sandbox, and the checkout has no git history.
|
|
12
|
+
|
|
13
|
+
## Built-in agents
|
|
14
|
+
|
|
15
|
+
### `codex` - OpenAI's Codex CLI
|
|
16
|
+
|
|
17
|
+
Runs `codex exec` with your user config and rules ignored, an ephemeral session, web
|
|
18
|
+
search and every feature that reaches beyond the checkout switched off. Shell commands
|
|
19
|
+
run in Codex's own `workspace-write` sandbox: no network, writes only in the checkout.
|
|
20
|
+
|
|
21
|
+
| Option | Meaning |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `reasoning-effort` | Passed through as `model_reasoning_effort`, e.g. `"high"`. |
|
|
24
|
+
| `local-provider` | `ollama` or `lmstudio`, to run an open model locally. |
|
|
25
|
+
|
|
26
|
+
### `claude-code` - Anthropic's Claude Code
|
|
27
|
+
|
|
28
|
+
Runs `claude --print` in safe mode, which leaves out CLAUDE.md, skills, plugins, hooks
|
|
29
|
+
and MCP servers. Edits are accepted only inside the checkout, shell commands run in
|
|
30
|
+
Claude Code's own sandbox, web tools are disallowed, and anything that would need a
|
|
31
|
+
person's approval is refused. `model` takes a full name or an alias such as `sonnet`.
|
|
32
|
+
|
|
33
|
+
| Option | Meaning |
|
|
34
|
+
|---|---|
|
|
35
|
+
| `effort` | Claude Code's effort level, e.g. `"high"`. |
|
|
36
|
+
|
|
37
|
+
### `gemini-cli` - Google's Gemini CLI
|
|
38
|
+
|
|
39
|
+
Runs `gemini --prompt` in auto-approve mode, with web tools excluded through workspace
|
|
40
|
+
settings. The whole process runs inside bugbout's sandbox: it can reach the Gemini API,
|
|
41
|
+
but write only in the checkout, its logs and `~/.gemini`.
|
|
42
|
+
|
|
43
|
+
### `mini-swe-agent` - any LiteLLM model
|
|
44
|
+
|
|
45
|
+
[mini-swe-agent](https://mini-swe-agent.com) is the SWE-bench team's minimal agent, and
|
|
46
|
+
the easiest way to race models rather than products - hosted or local. `model` is a
|
|
47
|
+
LiteLLM name such as `ollama/qwen3-coder:30b` and is required. Every shell command it
|
|
48
|
+
runs goes through bugbout's sandbox, with no network.
|
|
49
|
+
|
|
50
|
+
| Option | Meaning |
|
|
51
|
+
|---|---|
|
|
52
|
+
| `text-actions` | `true` for models whose server cannot parse tool calls reliably. |
|
|
53
|
+
| `step-limit` | The most steps per task; 75 by default. |
|
|
54
|
+
| `model-kwargs` | Extra model arguments, e.g. `{ temperature = "0" }`. |
|
|
55
|
+
|
|
56
|
+
For local models served by Ollama, give the server enough context for an agent, e.g.
|
|
57
|
+
`OLLAMA_CONTEXT_LENGTH=65536 ollama serve`.
|
|
58
|
+
|
|
59
|
+
### `command` - anything else with a command line
|
|
60
|
+
|
|
61
|
+
Any agent that can run unattended can join through configuration alone:
|
|
62
|
+
|
|
63
|
+
```toml
|
|
64
|
+
[[contestants]]
|
|
65
|
+
agent = "command"
|
|
66
|
+
name = "aider"
|
|
67
|
+
model = "gpt-5"
|
|
68
|
+
command = ["aider", "--yes-always", "--no-git", "--model", "{model}", "--message-file", "{prompt_file}"]
|
|
69
|
+
state-dirs = ["~/.aider"]
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
In `command`, these placeholders are filled in for each run:
|
|
73
|
+
|
|
74
|
+
| Placeholder | Becomes |
|
|
75
|
+
|---|---|
|
|
76
|
+
| `{prompt}` | The task prompt itself. |
|
|
77
|
+
| `{prompt_file}` | A file holding the prompt. |
|
|
78
|
+
| `{workdir}` | The checkout the agent works in (also its working directory). |
|
|
79
|
+
| `{logdir}` | A directory for the agent's own logs. |
|
|
80
|
+
| `{model}` | The configured model. |
|
|
81
|
+
|
|
82
|
+
Without `{prompt}` or `{prompt_file}`, the prompt arrives on standard input.
|
|
83
|
+
|
|
84
|
+
| Option | Meaning |
|
|
85
|
+
|---|---|
|
|
86
|
+
| `command` | The command line, as a list. Required. |
|
|
87
|
+
| `name` | Required, since there is no agent type to name it after. |
|
|
88
|
+
| `env` | Extra environment variables for the agent. |
|
|
89
|
+
| `state-dirs` | Directories outside the checkout the agent must write to, such as its own config. |
|
|
90
|
+
| `sandboxed` | `false` to run without bugbout's sandbox - only for agents that sandbox themselves. |
|
|
91
|
+
|
|
92
|
+
## Sandboxing
|
|
93
|
+
|
|
94
|
+
On macOS, bugbout uses seatbelt (`sandbox-exec`); on Linux, bubblewrap (`bwrap`, e.g.
|
|
95
|
+
`apt install bubblewrap`). Either way a sandboxed process can read anything, but write
|
|
96
|
+
only in the directories it was given and the system's temporary directories.
|
|
97
|
+
|
|
98
|
+
- An agent's **shell commands** get no network at all.
|
|
99
|
+
- An agent's **whole process**, where bugbout confines it (Gemini CLI, `command`
|
|
100
|
+
agents), keeps the network so it can reach its model.
|
|
101
|
+
- The **tests** bugbout runs - including tests an agent wrote - get no network and may
|
|
102
|
+
write only in their own checkout.
|
|
103
|
+
|
|
104
|
+
`sandbox = "none"` runs everything unconfined. `bugbout doctor` reports which sandbox
|
|
105
|
+
is in use, or why none can start. On Ubuntu 24.04 and later, AppArmor restricts the
|
|
106
|
+
unprivileged user namespaces bubblewrap needs; allow them for `bwrap` with an AppArmor
|
|
107
|
+
profile, or system-wide with `sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0`.
|
|
108
|
+
|
|
109
|
+
## Quotas and lanes
|
|
110
|
+
|
|
111
|
+
Agents are rate-limited by their plans, not by your machine, so a bout queues runs per
|
|
112
|
+
**quota**: runs sharing a quota take turns, and different quotas run in parallel. By
|
|
113
|
+
default an agent's quota is its type (all `codex` agents share a ChatGPT plan, say),
|
|
114
|
+
and one run per quota runs at a time. Raise that with `[run] quotas`, or move an agent
|
|
115
|
+
to its own lane with `quota = "..."`.
|
|
116
|
+
|
|
117
|
+
When an agent stops on a usage limit without producing anything, the attempt is marked
|
|
118
|
+
`quota`. `bugbout run --retry-failed` runs such attempts again once the limit resets;
|
|
119
|
+
finished attempts are never re-run.
|
|
120
|
+
|
|
121
|
+
## Writing an adapter in Python
|
|
122
|
+
|
|
123
|
+
An adapter says how to start the agent; bugbout does the rest - checkouts, timeouts,
|
|
124
|
+
logs, patches and scoring.
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
from pathlib import Path
|
|
128
|
+
|
|
129
|
+
from bugbout import CodingAgent, Invocation, Session
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class MyAgent(CodingAgent):
|
|
133
|
+
harness = "my-agent" # the default name prefix
|
|
134
|
+
executable = "my-agent" # what `bugbout doctor` looks for
|
|
135
|
+
|
|
136
|
+
def invocation(self, session: Session) -> Invocation:
|
|
137
|
+
argv = [self.command(), "--model", self.model, "--yes"]
|
|
138
|
+
return Invocation(argv, stdin=session.prompt)
|
|
139
|
+
|
|
140
|
+
def parse(self, logdir: Path) -> tuple[str, dict[str, int]]:
|
|
141
|
+
# Optional: the agent's closing summary and token usage, from its logs.
|
|
142
|
+
return (logdir / "stdout.log").read_text()[-2000:], {}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`Session` carries the prompt, the checkout (`workdir`), a log directory and the
|
|
146
|
+
sandbox; if the agent does not confine itself, wrap its command with
|
|
147
|
+
`session.sandbox.wrap(argv, Confinement(...))` (from `bugbout.sandbox`). Pass agents to a bout directly:
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
from bugbout import Bout, Project
|
|
151
|
+
|
|
152
|
+
report = Bout(Project.load("."), contestants=[MyAgent("my-model")]).run()
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
To make an adapter available to `bugbout.toml`, publish it with an entry point:
|
|
156
|
+
|
|
157
|
+
```toml
|
|
158
|
+
[project.entry-points."bugbout.agents"]
|
|
159
|
+
my-agent = "my_package.agent:MyAgent"
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
and use it as `agent = "my-agent"`.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
A bout is configured by `bugbout.toml`, usually at the root of your repository.
|
|
4
|
+
`bugbout init` writes one for you; every key below is optional except
|
|
5
|
+
`project.source`. Keys use dashes, as in `pyproject.toml`.
|
|
6
|
+
|
|
7
|
+
## `[project]` - the code under test
|
|
8
|
+
|
|
9
|
+
| Key | Default | Meaning |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| `source` | *required* | The package directory, relative to the repository root, e.g. `src/mypkg`. |
|
|
12
|
+
| `tests` | `"tests"` | The test directory. |
|
|
13
|
+
| `repository` | `"."` | The repository: a path relative to `bugbout.toml`, or a git URL to clone. |
|
|
14
|
+
| `github` | from `origin` | `owner/name` to read issues from, when `origin` is not on GitHub. |
|
|
15
|
+
| `python` | `"3.12"` | The Python version of the test environment. |
|
|
16
|
+
| `test-dependencies` | `["pytest"]` | What the tests need besides the project's own dependencies. |
|
|
17
|
+
| `pytest-args` | `[]` | Extra arguments for every test run. |
|
|
18
|
+
| `env` | `{}` | Extra environment variables for the tests, such as a database URL. |
|
|
19
|
+
| `install-project` | `true` | Install the project once to pull in its runtime dependencies. |
|
|
20
|
+
| `interpreter` | none | An existing Python to run tests with, instead of building an environment. |
|
|
21
|
+
|
|
22
|
+
bugbout builds one environment per project with uv. It holds the test dependencies and
|
|
23
|
+
the project's runtime dependencies but not the project itself: every checkout is put on
|
|
24
|
+
`PYTHONPATH`, so the code under test is always the tree being tested.
|
|
25
|
+
|
|
26
|
+
The project's own `addopts` are ignored, because they often need plugins the test
|
|
27
|
+
environment does not have (coverage, xdist). Put anything your tests really need in
|
|
28
|
+
`pytest-args`.
|
|
29
|
+
|
|
30
|
+
## `[tasks]` - which fixes become tasks
|
|
31
|
+
|
|
32
|
+
| Key | Default | Meaning |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| `since` | all history | Only consider changes after this date, e.g. `"2023-01-01"`. |
|
|
35
|
+
| `limit` | `20` | The most tasks to keep, newest first. |
|
|
36
|
+
| `max-source-files` | `2` | A fix that touches more source files than this is too broad to be one bug. |
|
|
37
|
+
|
|
38
|
+
## `[run]` - how agents run
|
|
39
|
+
|
|
40
|
+
| Key | Default | Meaning |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| `sandbox` | `"auto"` | `auto`, `seatbelt` (macOS), `bubblewrap` (Linux) or `none`. |
|
|
43
|
+
| `timeout` | `1800` | Seconds one agent may spend on one task. |
|
|
44
|
+
| `quotas` | `{}` | How many runs may share a quota at once, e.g. `{ codex = 2 }`. One by default. |
|
|
45
|
+
|
|
46
|
+
## `[judge]` - how a patch is picked
|
|
47
|
+
|
|
48
|
+
| Key | Default | Meaning |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| `policy` | `"majority"` | `majority`, `unanimous`, `strict` or `cross-vendor`; see [How it works](how-it-works.md#the-judge). |
|
|
51
|
+
| `run-suite` | `true` | Also run the repository's own tests against every patch, so breakage shows. Turn it off for very slow suites. |
|
|
52
|
+
|
|
53
|
+
## `[[contestants]]` - the agents that fix bugs
|
|
54
|
+
|
|
55
|
+
Each entry is one agent with one model.
|
|
56
|
+
|
|
57
|
+
| Key | Meaning |
|
|
58
|
+
|---|---|
|
|
59
|
+
| `agent` | The agent type: `codex`, `claude-code`, `gemini-cli`, `mini-swe-agent` or `command`. |
|
|
60
|
+
| `model` | The model to use. Leave it out to use the agent's own default (not allowed for `mini-swe-agent`). |
|
|
61
|
+
| `name` | How the agent appears in reports. Defaults to `agent/model`, or just `agent`. |
|
|
62
|
+
| `vendor` | Who made the model. Guessed from the model name; set it when the guess is wrong. |
|
|
63
|
+
| `quota` | The rate limit it shares with other agents. Defaults to the agent type. |
|
|
64
|
+
|
|
65
|
+
Any other key is passed to the agent's adapter; see [Agents](agents.md) for each one's
|
|
66
|
+
options. For example:
|
|
67
|
+
|
|
68
|
+
```toml
|
|
69
|
+
[[contestants]]
|
|
70
|
+
agent = "codex"
|
|
71
|
+
model = "gpt-5.1-codex"
|
|
72
|
+
reasoning-effort = "high"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## `[[examiners]]` - the agents that write tests
|
|
76
|
+
|
|
77
|
+
Examiners never fix anything. From the issue alone, they write tests that a correct fix
|
|
78
|
+
must pass, and those tests cross-examine every contestant's patch. An examiner takes
|
|
79
|
+
the same keys as a contestant, plus:
|
|
80
|
+
|
|
81
|
+
| Key | Default | Meaning |
|
|
82
|
+
|---|---|---|
|
|
83
|
+
| `assignment` | `"reproduce"` | `reproduce`: tests for exactly what the issue reports. `specify`: also the general rule behind it, and nearby behaviour a fix must keep. |
|
|
84
|
+
|
|
85
|
+
Examiners are optional. Without them, the contestants' own tests still cross-check each
|
|
86
|
+
other's patches.
|
|
87
|
+
|
|
88
|
+
## Environment variables
|
|
89
|
+
|
|
90
|
+
| Variable | Meaning |
|
|
91
|
+
|---|---|
|
|
92
|
+
| `BUGBOUT_HOME` | Where environments and checkouts are cached; `~/.cache/bugbout` by default. |
|
|
93
|
+
| `GITHUB_TOKEN` | Read issues with a token. Without one, bugbout uses the GitHub CLI's login, or anonymous access at 60 requests an hour. |
|
|
94
|
+
|
|
95
|
+
Agents read their own credentials as usual - for example `GEMINI_API_KEY` for Gemini
|
|
96
|
+
CLI, or whatever a LiteLLM model needs for mini-swe-agent.
|
|
97
|
+
|
|
98
|
+
## Where things are kept
|
|
99
|
+
|
|
100
|
+
Results live with your project, in `.bugbout/` beside `bugbout.toml`. That directory
|
|
101
|
+
ignores itself in git; delete its `.gitignore` if you want to commit results.
|
|
102
|
+
|
|
103
|
+
| Path | Holds |
|
|
104
|
+
|---|---|
|
|
105
|
+
| `tasks.json` | The mined tasks, and why other fixes were left out. |
|
|
106
|
+
| `oracles.json` | Each task's ground truth. |
|
|
107
|
+
| `attempts/` | One file per agent per task: how the run went, and its patch. |
|
|
108
|
+
| `matrices/` | Every test's outcome on every patch, per task. |
|
|
109
|
+
| `verdicts.json`, `resolutions.json` | The judge's picks, and every patch's score. |
|
|
110
|
+
| `report.md`, `report.json` | The report from the last `bugbout run`. |
|
|
111
|
+
|
|
112
|
+
Heavy, disposable state - test environments, checkouts and the agents' working copies
|
|
113
|
+
with their logs - lives in `BUGBOUT_HOME`, never in your repository.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# How it works
|
|
2
|
+
|
|
3
|
+
A bout replays bugs your project has already fixed. Because the fix and its tests are
|
|
4
|
+
known, every agent's patch can be scored by the maintainers' own judgement - without
|
|
5
|
+
asking a model whether it looks right.
|
|
6
|
+
|
|
7
|
+
## 1. Mining tasks
|
|
8
|
+
|
|
9
|
+
bugbout walks the first-parent history of your default branch, so each change that
|
|
10
|
+
landed is seen once: a squashed commit, a rebased one, or a pull request's merge commit.
|
|
11
|
+
A change becomes a task when:
|
|
12
|
+
|
|
13
|
+
- its title reads like a fix (*fix*, *bug*, *crash*, *regression*, ...);
|
|
14
|
+
- it changes at most `max-source-files` Python files in the package;
|
|
15
|
+
- it adds at least one test function to a test module;
|
|
16
|
+
- it names an issue or pull request, such as `(#123)` or `Fixes #45`.
|
|
17
|
+
|
|
18
|
+
The task's problem statement is the text of that issue. When a pull request links the
|
|
19
|
+
issue it closes, the issue's own text is used instead, because it describes the problem
|
|
20
|
+
without knowing the answer. Sections in which an author describes their fix
|
|
21
|
+
(*Solution*, *Changes*, ...) and diff blocks are removed. If several changes point at
|
|
22
|
+
the same issue, only the newest one is kept.
|
|
23
|
+
|
|
24
|
+
## 2. Ground truth
|
|
25
|
+
|
|
26
|
+
For each task, the test modules the fix touched are run twice: on the code just before
|
|
27
|
+
the fix, with the fix's versions of those tests installed, and on the fix itself. The
|
|
28
|
+
same definitions as SWE-bench follow:
|
|
29
|
+
|
|
30
|
+
- **fail-to-pass** tests fail before the fix and pass after it: a correct patch must
|
|
31
|
+
make them all pass;
|
|
32
|
+
- **pass-to-pass** tests pass on both sides: a correct patch must keep them passing.
|
|
33
|
+
|
|
34
|
+
The fixed tree is run twice, and any test whose outcome differs between the two runs is
|
|
35
|
+
set aside as unstable. A task where the fix made no test go from failing to passing
|
|
36
|
+
proves nothing and is not scored.
|
|
37
|
+
|
|
38
|
+
## 3. The race
|
|
39
|
+
|
|
40
|
+
Every contestant gets the same prompt: the issue's text, a request to fix it and add a
|
|
41
|
+
regression test, and a command that runs the project's tests. Its working copy is the
|
|
42
|
+
code just before the fix, with:
|
|
43
|
+
|
|
44
|
+
- no `.git` directory, so neither the fix nor any later commit can be read;
|
|
45
|
+
- none of the fix's test files;
|
|
46
|
+
- web tools off and commands sandboxed (see [Agents](agents.md#sandboxing)).
|
|
47
|
+
|
|
48
|
+
Each attempt runs in a fresh copy, and what changed on disk *is* the patch - whatever
|
|
49
|
+
the agent says it did. Attempts are saved as they finish, so a bout can stop and resume
|
|
50
|
+
at any time without spending an agent's quota twice.
|
|
51
|
+
|
|
52
|
+
Examiners, if any are configured, get the same checkout and the issue, but are told to
|
|
53
|
+
fix nothing: only to write tests that capture the bug - checked to fail on the unfixed
|
|
54
|
+
code for the reason the issue describes.
|
|
55
|
+
|
|
56
|
+
## 4. Scoring
|
|
57
|
+
|
|
58
|
+
A patch is scored by applying its source changes - never its edits to the tests - to the
|
|
59
|
+
code before the fix, installing the maintainers' test files from the fix, and running
|
|
60
|
+
them. It **resolves** the task when every fail-to-pass test passes and no pass-to-pass
|
|
61
|
+
test fails. The report also separates patches that fixed the bug but broke something
|
|
62
|
+
else, patches that left the bug in place, and attempts that produced no fix.
|
|
63
|
+
|
|
64
|
+
## 5. Cross-examination
|
|
65
|
+
|
|
66
|
+
Before anyone looks at the hidden tests, every test the agents wrote is run against
|
|
67
|
+
every patch:
|
|
68
|
+
|
|
69
|
+
- each contestant's regression test, against everyone else's fix;
|
|
70
|
+
- each examiner's tests, which never saw a patch;
|
|
71
|
+
- and the repository's existing suite, so breakage shows without anyone predicting it.
|
|
72
|
+
|
|
73
|
+
Each author's tests are installed under a module name of their own, so none can shadow
|
|
74
|
+
another's. The result is a matrix of executed outcomes - no model is asked anything.
|
|
75
|
+
|
|
76
|
+
## The judge
|
|
77
|
+
|
|
78
|
+
The judge reads the matrix and picks one patch per task, or refuses to. Every rule is
|
|
79
|
+
about executed tests, so every verdict can be traced to cells in the matrix:
|
|
80
|
+
|
|
81
|
+
1. **A reproduction must reproduce.** A test counts as evidence about the bug only if it
|
|
82
|
+
fails on the unfixed code.
|
|
83
|
+
2. **Nobody vouches for themselves.** A patch is supported only by other authors' tests.
|
|
84
|
+
3. **Breaking something needs a quorum.** A repository test the patch breaks counts
|
|
85
|
+
against it only if most other patches keep it passing; when nearly every patch
|
|
86
|
+
changes it, the issue probably asked for that change.
|
|
87
|
+
4. **Abstain rather than guess.** Without enough independent support, there is no pick.
|
|
88
|
+
|
|
89
|
+
| Policy | Approves a patch that passes... |
|
|
90
|
+
|---|---|
|
|
91
|
+
| `majority` | at least half of the independent reproductions, on average across authors. |
|
|
92
|
+
| `unanimous` | every independent reproduction. |
|
|
93
|
+
| `strict` | every independent reproduction, and breaks none of the examiners' tests for behaviour the issue does not ask to change. |
|
|
94
|
+
| `cross-vendor` | as `majority`, but no vendor's tests may support its own models. |
|
|
95
|
+
|
|
96
|
+
## The report
|
|
97
|
+
|
|
98
|
+
- **Agents** - each contestant's patches against the ground truth: resolved, fixed but
|
|
99
|
+
broke a test, wrong fix, no fix.
|
|
100
|
+
- **Picking one patch per bug** - the judge's picks against the best single agent, an
|
|
101
|
+
agent chosen at random, and the best any choice could do.
|
|
102
|
+
- **Every patch through a merge gate** - each patch judged alone, as if one agent had
|
|
103
|
+
just said it was done: how often an approval was right, and how many wrong patches
|
|
104
|
+
were stopped.
|
|
105
|
+
- **Which tests tell a right fix from a wrong one** - for each author of tests, and for
|
|
106
|
+
your own suite, how well their outcomes separate correct patches from wrong ones.
|
|
107
|
+
- **How the tasks were found** - how much history was examined, and why fixes were left
|
|
108
|
+
out.
|