---
name: multi-agent-bug-bash
description: "Bug bash: parallel exploratory sessions by charter and persona, each with a budget; a finding is reported only when a repro test fails for its reason. Use when an app or branch needs broad bug hunting."
user-invocable: true
argument-hint: "[scope] [--platform ios|android|web] [--charters <file>]  -  scope: an area, a branch to diff against its base, or empty for the whole app"
metadata:
  language: en
  not-for: test, review, scenario-audit
---

# multi-agent-bug-bash

**Input**: $ARGUMENTS

Several exploratory sessions run at once, each on one area with one posture.
What they report are claims. A claim becomes a bug in the report only when a
reproducing test fails with `ASSERTION_FAILED` on the assertion that encodes it;
everything else is listed as rejected, with the reason.

Scripts: `$HOME/.claude/scripts/bug-bash.mjs` (charters, merge, proof rule),
`$HOME/.claude/scripts/explore-findings.mjs` (per-session budget, stop rules,
judge). Contracts, read before Step 1:

```
$HOME/.claude/multi-agent-refs/features/exploratory-testing.md
$HOME/.claude/multi-agent-refs/features/assertion-judge.md
```

Log dir: `$HOME/.claude/logs/bug-bash/{repo}/{timestamp}/` (`LOG` below).

## Gotchas

- "The explorer reported it" is not "confirmed". No passing proof, no bug.
- One charter, one area. A charter that spans the app ends at its budget having skimmed everything.
- Explorers that share an account report each other's edits as bugs: one test account per charter, typed by `secret_ref`.
- Against a deployed environment other people use, the bash is read-only: no sign-ups, purchases, submissions or injection-shaped input. A firewall block is the firewall working, not a finding.
- Mobile explorers need one booted device each; web explorers one browser `session` each.

## Step 1 - Prepare

1. Platform: `--platform`, else detect as `multi-agent-test` does. Mobile: list
   booted devices; the parallel width is `min(4, devices)`. Web: the app URL,
   width 4.
2. Toolkit: locators, expect steps, verdict codes, `secret_ref`, `trace.md`,
   web `session` and `save_as` / `replay` need
   `@mmerterden/multi-agent-toolkit-mcp` ≥ v3.19.0. On an older server, say so
   once and run with UI-tree taps; the proof rule does not change.
3. Ask (one question to the user) for what the local app cannot do: integrations
   without keys, seed data, what must never be tapped (payments, real
   accounts), and the test accounts by credential name. This becomes the
   charter context and the triage reference for Step 5.

## Step 2 - Charters

With `--charters <file>`, use it. Otherwise read the screens, navigation and
forms (for a branch, `git diff --stat` against its base) and write 5-10
charters to `$LOG/charters.json`:

```json
[{"slug": "cart", "persona": "skeptic", "area": "Cart", "start": "Cart tab",
  "goal": "Starting at the Cart tab, change quantities and check every total against its rows",
  "budget": {"steps": 6, "minutes": 10, "tokens": 120000}, "account": "bb-cart"}]
```

Personas: `first-time-user`, `skeptic` (numbers and copy), `fuzzer` (edge
input; name the exact matrix in the goal), `state-keeper` (relaunch, back,
reload), `error-paths`, or `custom` with `stance`. Validate:

```bash
node "$HOME/.claude/scripts/bug-bash.mjs" charters --file "$LOG/charters.json"
```

Exit 1 lists what to fix. Show the charters in one table and confirm once
(autopilot: proceed).

## Step 3 - Fan out

One explorer subagent per charter, at most the Step 1 width at a time (one task
each where the host can start them, otherwise sequentially). Each gets
its charter, the persona's stance, the Step 1 context, its device or session,
and these orders:

- Write `$LOG/sessions/<slug>.json` in the explore-run shape as you go: goal,
  persona, platform, budget, usage, steps, findings.
- Run `explore-findings.mjs check --run <file>` before every step; stop when
  it says so.
- Report every finding with expected, observed, repro, severity 1-5, kind and
  evidence on disk. Credentials by `secret_ref` only.
- A visual or semantic claim is decided by a fresh judge (assertion-judge.md),
  not by you.
- Never fix anything, never commit.

A session that ends `blocked` is kept: its causes go in the report.

## Step 4 - Merge

```bash
node "$HOME/.claude/scripts/bug-bash.mjs" merge --sessions "$LOG/sessions" > "$LOG/merged.json"
```

Candidates `BB-1..n` merge one defect seen by several charters. Warnings and
findings that failed the contract are kept apart.

## Step 5 - Triage, then verify

Sort every candidate before writing any test; read the source to do it.

| Bucket | Sign | Outcome |
|---|---|---|
| artifact | the explorer misread: lazy content not loaded, text split in the tree but whole on screen, a sheet it never scrolled | `rejected` with the check that settled it |
| environment | fails on a key, service or limit only the local stack lacks | `rejected`; `productionRisk: true` when production users would see the bad handling |
| design | code, tests or copy say it is intended | `rejected`, citing where |
| fixture | seed data lacks what real records have | `rejected`, naming the field |
| candidate | none of the above | verify |

Verify with one subagent per area (up to the Step 1 width), each with its
candidates and these orders:

1. Read `observed` against the evidence; a contradiction rejects it here.
2. Write a repro test in the project's own UI test framework (XCUITest,
   Compose / Espresso, Playwright), or as a toolkit step sequence saved with
   `save_as` whose last step is an `expect_*` assertion. It follows the repro
   and asserts `expected`, so it fails today and passes once fixed. Put it under
   a `BugBash` / `bugbash` directory and keep it out of the gating suite.
3. Run it alone. Confirmed only when it fails with `ASSERTION_FAILED` on the
   assertion that encodes the finding (`failedAt` equals `assertion`). A
   failing XCTest / JUnit / Playwright `expect` on that line counts as
   `ASSERTION_FAILED`; a build error, timeout, missing element or a different
   assertion means the test is wrong: fix it and rerun. A passing test means
   the finding did not reproduce.
4. Record `$LOG/verifications.json` entries:
   `{id, status, repro: {path, command, code, assertion, failedAt, trace?}, rootCause?, reason?, note?, productionRisk?}`.

## Step 6 - Report

```bash
node "$HOME/.claude/scripts/bug-bash.mjs" report --merged "$LOG/merged.json" \
  --verifications "$LOG/verifications.json" > "$LOG/report.md"
```

The script demotes any confirmed entry without a passing proof to `unproven`
and any candidate without an entry to `unverified`. Print the report: confirmed
bugs first (repro test, root cause, evidence, charters), then unverified
production risks, rejected by reason, warnings, and the charter table. Close
with the areas no charter reached and which parts are mechanical (the proof
rule, the stop rules) versus judgement (triage, the charters themselves).

Then offer, one question: fix the confirmed bugs through `multi-agent` with
each repro test as the acceptance check (green test = fixed, kept as the
regression test), or stop. **No commit, no push, no issue from this command.**
