bb-workflow
The driver is the plan. You run one command, do exactly what it prints, record the result, repeat.
Nothing here is advisory: the gates are enforced by scripts/campaign.py, so follow its output
literally rather than improvising. This exists because prose routing failed - 22 Skill calls against
341 hand-rolled curls in the reference campaign; the board fixes that by making the mandate tool
output, fresh every turn.
The loop
python3 scripts/campaign.py next # prints ONE required-action block # do EXACTLY what it lists, in order python3 scripts/campaign.py note <row> --arsenal <slug> # after Skill(wiki-arsenal) python3 scripts/campaign.py done <row> --poc <img> --kind req # | --dead R | --park Q | --find F # repeat
Start / resume
python3 scripts/campaign.py init --type bb- validatesscope.md+ the autonomy envelope, repairsengagement_type/schema, prints the Deadends size. If it exits 2, fix what it names (an emptyscope.mdis the one thing it cannot invent - fill it from the programme brief first).- Passes 0-3 (OSINT/Wayback, crawl, fingerprint, CVE) feed
state.md. Read every JS bundle and handler end to end (Skill-less; volume-reduce first: source-map, drop vendor, beautify, read). Grep never substitutes for the read. python3 scripts/campaign.py board- writes the killchain 4a rows. Refuses on an empty state.- Enter the loop.
nextserves one row, depth-first, one open row at a time.
Browser observation (chrome-devtools MCP)
The programme's targets are internet-reachable, so drive them through a real browser, not just
curl - a modern site's real attack surface is only visible rendered. Use the chrome-devtools MCP:
- Pass 1 crawl:
navigate_pageto each app, thenlist_network_requests- the XHR/fetch calls a page makes reveal the API endpoints/routes a static crawl never sees (this is exactly the lead a curl-only recon misses).take_snapshotfor the rendered DOM;evaluate_scriptto read client config /__NEXT_DATA__/ JS globals. - Confirmation + evidence: DOM-XSS fires in the real DOM (
evaluate_script/ console); a renderedtake_screenshotof the exploited state is a validwebPoC (G3).
Caveat: chrome-devtools drives a local browser, so it only reaches internet targets. For a
VPN-boxed host it cannot connect - use the VM-side browser (scripts/browser.sh / capture.sh web)
as the equivalent. pt-workflow / ctf-workflow default to the VM browser for that reason.
Manual login / MFA the agent cannot do headlessly (Smart-ID, Mobile-ID, a CAPTCHA) -> Skill(chrome-devtools-browser): a VISIBLE chromium on the VM desktop (scripts/browser-visible.sh) the operator logs into, driven + observed live via the chrome-devtools MCP - capture the authenticated session and the real /… API calls, then feed the hunt skills.
Gates (the driver enforces; do not fight them)
- G1 no exploit action until the row's arsenal card exists (
Skill(wiki-arsenal)fills it). - G2 a row cannot close unless its mapped
Skill(hunt-*)actually fired. - G3 a row cannot close without typed evidence:
req(default),burp, orweb(visual classes only). A page render is not evidence of a bug. - G8 run the mapped tool before hand-rolling; the driver warns if you skipped it.
Autonomy
No approvals. Out-of-envelope work parks to decisions.md and the loop moves on - it never blocks
and never asks a question. A confirmed TIER1 is written up and chained but does not stop the run; the
campaign ends when the board is exhausted (two dry reframe rounds) or the request budget is spent.
Model routing
Explicit per-role model assignment (the driver enforces the verifier gate; the rest is operating policy):
- Main brain - Opus 5 1M: the
campaign.pyloop, board/state, strategy, Burp/chrome-devtools, finding write-ups. This session. - Verifier - Opus (fresh context), MANDATORY: before any CONFIRMED,
campaign.py verify <F>prints an Opus refuter prompt; dispatch ONE fresh Opus agent that reads the raw PoC, tries to REFUTE, and writesverdicts/<F>.json.done --findrefuses unless that verdict exists, isrefuted:false, and cites the finding's PoC (anti-rubber-stamp). Fails CLOSED. - RTL - Opus (fresh context):
Skill(redteamlead)for direction at a fork or when a vector stalls. - Short tasks - Haiku:
Skill(wiki-arsenal)deep,Skill(delegate)(mechanical exploit-run),Skill(ingest)recon-parse. Bounded, fully-specified, single-shot ONLY.
The line that keeps quota safety: Haiku is allowed for a bounded single job, never for open-ended parallel hunting.
Discipline (carried, not restated - hunt-core owns the gates)
- Do NOT invoke
superpowers:brainstormingorsuperpowers:writing-plansmid-campaign, and keep no parallelTaskCreatelist. The board is the plan. - Model routing (see
## Model routing): Opus-1M drives the loop; bounded short tasks go to Haiku; the mandatory Opus verifier gates every finding (done --findrefuses without a passingverdicts/<F>.json). Still no open-ended hunter fan-out (it exhausted the weekly quota last time) - Haiku is only for single, fully-specified jobs. - Load-bearing exploit requests go through Burp Repeater when it is reachable; degrade to
capture.sh reqwhen it is not. Never block on Burp. - Scope and the enumeration ceiling come from
scope.md, never from this skill. - RCE-first: with >1 vector open, take the code-exec one first - it is the attack vector with impact; chase lower-impact classes only after code-exec is ruled out or the target needs them.
- Read whole, not grep: on a post-foothold host where a sudoer has no findable password and the
usual vectors dead-end, READ
/etc/pam.d/{sudo,su}+/etc/sudoers.d/*and linpeas output WHOLE - apam_ssh_agent_auth/pam_exec/NOPASSWDline is the tell a grep skips. See [[linux-privesc]]. - Long tools: run pspy/linpeas via
bash scripts/vm-bg.sh <eng> <win> '<tool>'(stages to/dev/shm, runs in the stabilized shell,--read/--wait 120the logfile); never retry a broken tool pattern >2x - switch method or callSkill(redteamlead).
Close-out
When next prints the close-out chain, run it: Skill(triage) -> Skill(evidence) ->
Skill(report) -> Skill(learn).
If the driver is unavailable
Manual fallback, same gates by hand: read Approach.md, take the top open row for the current
asset, run its wiki lookup then its hunt skill, capture req evidence, mark it [x]; on exhaustion
one Deadends.md line and [!].


