| name | bisect |
| description | Binary search for root cause: define a search space and a pass/fail oracle, then halve the space each step until the culprit commit, config key, or dependency is isolated. Works across git history, configuration, dependencies, or code modules. |
| scope | universal |
| ported-from | bisect command |
Bisect: Binary Search for Root Cause
Define a search space and a pass/fail oracle, then iteratively test midpoints,
halving the space each step until the root cause is isolated. Works across git
history, configuration, dependencies, or code modules.
Arguments
"description of the bug or regression"
- A description of the symptom or regression is the search target.
- Missing or unclear: ask the user to clarify the symptom before starting.
Phase 1: Define the Search Space
Work with the user to establish four things before starting the search loop.
1. The symptom: what is broken? What does failure look like? Get a concrete, observable description (error message, wrong output, crash, performance degradation).
2. The search dimension: where to search. Determine which applies:
- Git history: a known-good commit and a known-bad commit (classic git bisect)
- Configuration space: a set of config keys that might cause the issue
- Dependency versions: which dependency upgrade broke things
- Code modules: which module is responsible for the regression
3. The test oracle: how to determine pass/fail at each midpoint:
- A specific test command (
npm test, pytest tests/foo.py, go test ./..., etc.)
- A behavior check (does endpoint X return 200? does the build succeed?)
- A manual check (agent reads code or output and assesses)
4. Known bounds: the "good" end and "bad" end of the search space.
For git history bisect, run:
git log --oneline <good_commit>..<bad_commit>
to enumerate the search space. Count the candidates and report: "Search space: N commits. Expected steps: ceil(log2(N))."
For configuration bisect, list all changed config keys between the working and broken state. For dependency bisect, list all upgraded packages with old and new versions sorted by update date.
Present the search space summary to the user and confirm before proceeding. Adjust if the user gives feedback.
Phase 2: Binary Search Loop
Execute the bisect algorithm. This is strictly sequential, each step depends on the previous result.
iteration = 0
while search_space > 1:
iteration += 1
midpoint = calculate_midpoint(search_space)
# Spawn a test agent at the midpoint
agent = spawn_test_agent(midpoint, test_oracle)
result = agent.run() # PASS or FAIL
if result == FAIL:
# Bug exists at midpoint: narrow to the first half
bad_bound = midpoint
else:
# Bug absent at midpoint: narrow to the second half
good_bound = midpoint
report_progress(iteration, midpoint, result, remaining_space)
Git History Bisect
At each midpoint commit, spawn an agent with subagent_type: "general-purpose" that:
- Uses
isolation: "worktree" to run in an isolated copy of the repo checked out at the midpoint commit
- Runs the test oracle inside the worktree
- Reports PASS or FAIL with evidence (test output, error message, or behavioral observation)
- Removes the worktree when done (
git worktree remove /tmp/bisect-<short_sha>)
- Does NOT modify the main working tree
Configuration Bisect
Sort the changed config keys into a list. At each step:
- Split the remaining keys into two halves
- Apply only the first half of changes (revert the second half to known-good values)
- Run the test oracle
- PASS means the bug is in the reverted half; FAIL means it is in the applied half
Dependency Bisect
Sort dependencies by update date. At each step:
- Split the remaining upgrades into two halves
- Revert the second half to their old versions
- Run the test oracle
- PASS means the culprit is in the reverted half; FAIL means it is in the applied half
Progress Reporting
After each iteration, report to the user:
Step N: Testing [midpoint identifier]
Result: PASS / FAIL
Remaining search space: M candidates
Narrowed to: [new bounds description]
Inconclusive Results
If a midpoint produces an inconclusive result (flaky test, build failure unrelated to the bug, untestable state), stop and ask the user:
- Skip: mark this midpoint as untestable and pick an adjacent point
- Abort: stop the bisect and report findings so far
Phase 3: Root Cause Identification
Once the search space narrows to a single item (one commit, one config key, one dependency):
- Identify the root cause: state the specific commit, config change, or dependency that introduced the regression
- Analyze the change: read the diff or changelog and explain WHY it caused the failure. For git bisect, run
git show <culprit_commit> and walk through the relevant hunks
- Propose a fix: suggest a concrete remediation: revert, patch, pin version, or redesign
- Check for related issues: search the codebase for similar patterns that might harbor the same bug
Phase 4: Report
Present the final report:
Root Cause
The specific change that introduced the regression, with a one-line summary.
Bisect Log
A table of every step: iteration number, midpoint tested, result (PASS/FAIL), remaining search space after that step.
Analysis
Why the identified change caused the regression. Include relevant code snippets or config values.
Fix Options
Ranked remediation paths:
- Immediate fix (revert or pin)
- Proper fix (patch the root cause)
- Long-term fix (redesign if the pattern is fragile)
Search Efficiency
How many steps were taken versus the theoretical minimum of ceil(log2(N)). Note any skipped midpoints.
Rules
- Sequential by necessity: each step depends on the previous result. Do NOT parallelize the bisect loop.
- Non-destructive: test agents must NOT modify the main working tree. Use git worktrees for git bisects. Clean up worktrees after each step.
- Clear oracle: if the test oracle is ambiguous or produces inconsistent results, stop and clarify with the user before continuing.
- Report every step: the user should see the search narrowing in real time. Never batch multiple steps silently.
- Bail out option: if the search hits an inconclusive result, ask the user whether to skip or abort.
- Maximum depth: cap at 20 iterations (covers 2^20 = ~1M candidates). If the search space is larger, ask the user to narrow the bounds first.
- Worktree hygiene: always remove temporary worktrees, even on failure. Run
git worktree prune at the end of a git bisect.
- No file modification: the bisect skill is read-only and diagnostic. It identifies the root cause and proposes a fix but does not apply changes unless the user explicitly asks.
Pipeline Position
Standalone debugging tool. Does not chain with the ideation-to-implementation pipeline:
bug report / regression → /bisect → root cause + fix proposal