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.
Files changed (97) hide show
  1. bugbout-0.1.0/.gitignore +27 -0
  2. bugbout-0.1.0/CHANGELOG.md +15 -0
  3. bugbout-0.1.0/LICENSE +21 -0
  4. bugbout-0.1.0/PKG-INFO +120 -0
  5. bugbout-0.1.0/README.md +88 -0
  6. bugbout-0.1.0/docs/agents.md +162 -0
  7. bugbout-0.1.0/docs/configuration.md +113 -0
  8. bugbout-0.1.0/docs/how-it-works.md +108 -0
  9. bugbout-0.1.0/pyproject.toml +89 -0
  10. bugbout-0.1.0/src/bugbout/__about__.py +1 -0
  11. bugbout-0.1.0/src/bugbout/__init__.py +60 -0
  12. bugbout-0.1.0/src/bugbout/__main__.py +5 -0
  13. bugbout-0.1.0/src/bugbout/agents/__init__.py +26 -0
  14. bugbout-0.1.0/src/bugbout/agents/base.py +287 -0
  15. bugbout-0.1.0/src/bugbout/agents/claude_code.py +107 -0
  16. bugbout-0.1.0/src/bugbout/agents/codex.py +105 -0
  17. bugbout-0.1.0/src/bugbout/agents/command.py +83 -0
  18. bugbout-0.1.0/src/bugbout/agents/gemini_cli.py +73 -0
  19. bugbout-0.1.0/src/bugbout/agents/mini_swe.py +103 -0
  20. bugbout-0.1.0/src/bugbout/agents/plugins/bugbout_mini_env.py +27 -0
  21. bugbout-0.1.0/src/bugbout/agents/registry.py +63 -0
  22. bugbout-0.1.0/src/bugbout/agents/vendors.py +36 -0
  23. bugbout-0.1.0/src/bugbout/arena/__init__.py +30 -0
  24. bugbout-0.1.0/src/bugbout/arena/briefs.py +176 -0
  25. bugbout-0.1.0/src/bugbout/arena/exhibits.py +78 -0
  26. bugbout-0.1.0/src/bugbout/arena/judge.py +301 -0
  27. bugbout-0.1.0/src/bugbout/arena/matrix.py +189 -0
  28. bugbout-0.1.0/src/bugbout/arena/race.py +266 -0
  29. bugbout-0.1.0/src/bugbout/bout.py +316 -0
  30. bugbout-0.1.0/src/bugbout/cli/__init__.py +5 -0
  31. bugbout-0.1.0/src/bugbout/cli/main.py +168 -0
  32. bugbout-0.1.0/src/bugbout/config.py +145 -0
  33. bugbout-0.1.0/src/bugbout/doctor.py +83 -0
  34. bugbout-0.1.0/src/bugbout/errors.py +39 -0
  35. bugbout-0.1.0/src/bugbout/home.py +22 -0
  36. bugbout-0.1.0/src/bugbout/jsonfile.py +34 -0
  37. bugbout-0.1.0/src/bugbout/log.py +30 -0
  38. bugbout-0.1.0/src/bugbout/naming.py +12 -0
  39. bugbout-0.1.0/src/bugbout/project.py +129 -0
  40. bugbout-0.1.0/src/bugbout/py.typed +0 -0
  41. bugbout-0.1.0/src/bugbout/report/__init__.py +19 -0
  42. bugbout-0.1.0/src/bugbout/report/build.py +218 -0
  43. bugbout-0.1.0/src/bugbout/report/markdown.py +161 -0
  44. bugbout-0.1.0/src/bugbout/report/model.py +162 -0
  45. bugbout-0.1.0/src/bugbout/report/terminal.py +42 -0
  46. bugbout-0.1.0/src/bugbout/report/text.py +38 -0
  47. bugbout-0.1.0/src/bugbout/sandbox/__init__.py +51 -0
  48. bugbout-0.1.0/src/bugbout/sandbox/base.py +60 -0
  49. bugbout-0.1.0/src/bugbout/sandbox/bubblewrap.py +80 -0
  50. bugbout-0.1.0/src/bugbout/sandbox/seatbelt.py +71 -0
  51. bugbout-0.1.0/src/bugbout/scaffold.py +135 -0
  52. bugbout-0.1.0/src/bugbout/store.py +125 -0
  53. bugbout-0.1.0/src/bugbout/tasks/__init__.py +18 -0
  54. bugbout-0.1.0/src/bugbout/tasks/issues.py +149 -0
  55. bugbout-0.1.0/src/bugbout/tasks/mining.py +205 -0
  56. bugbout-0.1.0/src/bugbout/tasks/oracle.py +187 -0
  57. bugbout-0.1.0/src/bugbout/tasks/task.py +60 -0
  58. bugbout-0.1.0/src/bugbout/workspace/__init__.py +8 -0
  59. bugbout-0.1.0/src/bugbout/workspace/environment.py +225 -0
  60. bugbout-0.1.0/src/bugbout/workspace/junit.py +29 -0
  61. bugbout-0.1.0/src/bugbout/workspace/patch.py +261 -0
  62. bugbout-0.1.0/src/bugbout/workspace/repository.py +139 -0
  63. bugbout-0.1.0/src/bugbout/workspace/workspace.py +85 -0
  64. bugbout-0.1.0/tests/__init__.py +0 -0
  65. bugbout-0.1.0/tests/agents/__init__.py +0 -0
  66. bugbout-0.1.0/tests/agents/test_adapters.py +212 -0
  67. bugbout-0.1.0/tests/agents/test_mini_env.py +41 -0
  68. bugbout-0.1.0/tests/agents/test_registry.py +52 -0
  69. bugbout-0.1.0/tests/agents/test_running.py +98 -0
  70. bugbout-0.1.0/tests/agents/test_vendors.py +24 -0
  71. bugbout-0.1.0/tests/arena/__init__.py +0 -0
  72. bugbout-0.1.0/tests/arena/test_judge.py +135 -0
  73. bugbout-0.1.0/tests/arena/test_matrix.py +99 -0
  74. bugbout-0.1.0/tests/arena/test_race.py +155 -0
  75. bugbout-0.1.0/tests/cli/__init__.py +0 -0
  76. bugbout-0.1.0/tests/cli/test_cli.py +116 -0
  77. bugbout-0.1.0/tests/conftest.py +25 -0
  78. bugbout-0.1.0/tests/processes.py +18 -0
  79. bugbout-0.1.0/tests/report/__init__.py +0 -0
  80. bugbout-0.1.0/tests/report/test_report.py +149 -0
  81. bugbout-0.1.0/tests/sandbox/__init__.py +0 -0
  82. bugbout-0.1.0/tests/sandbox/test_sandbox.py +128 -0
  83. bugbout-0.1.0/tests/tasks/__init__.py +0 -0
  84. bugbout-0.1.0/tests/tasks/test_issues.py +51 -0
  85. bugbout-0.1.0/tests/tasks/test_mining.py +177 -0
  86. bugbout-0.1.0/tests/tasks/test_oracle.py +81 -0
  87. bugbout-0.1.0/tests/test_bout.py +112 -0
  88. bugbout-0.1.0/tests/test_doctor.py +31 -0
  89. bugbout-0.1.0/tests/test_project.py +125 -0
  90. bugbout-0.1.0/tests/test_scaffold.py +74 -0
  91. bugbout-0.1.0/tests/test_store.py +63 -0
  92. bugbout-0.1.0/tests/toy.py +138 -0
  93. bugbout-0.1.0/tests/workspace/__init__.py +0 -0
  94. bugbout-0.1.0/tests/workspace/test_environment.py +123 -0
  95. bugbout-0.1.0/tests/workspace/test_junit.py +30 -0
  96. bugbout-0.1.0/tests/workspace/test_patch.py +97 -0
  97. bugbout-0.1.0/tests/workspace/test_repository.py +92 -0
@@ -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)
@@ -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.