Red vs Blue team security competition orchestrator. Runs long-running overnight battles with 1000s of interactions, scoring, and insight generation.
STOP. READ THIS ENTIRE SKILL.MD BEFORE CALLING ANY ENDPOINT.
Red vs Blue Team Security Competition Orchestrator
Pits a Red Team (attack) against a Blue Team (defense) in a long-running competitive loop. Each team leverages all .pi/skills to attack or defend a target codebase.
Battle's default scoring targets exploitation (system-down, command injection), but the most frequent real use of an adversarial Red/Blue loop is verifying a PROJECT-SPECIFIC INVARIANT: "no PII value leaks", "the ledger balances", "the parser drops no record", "the authz check cannot be bypassed".
Supply a pluggable invariant Judge -- a small independent module
judge(target_dir, params) -> {passed, violations, evidence} (schema
battle.invariant_result.v1). Red's objective becomes "produce an input that
makes the Judge fail"; Blue's is "make it pass"; the scorekeeper reads the Judge
result, never an agent's self-report. Judges are fail-closed: a judge that
errors is a FAILED invariant, never a silent pass.
python3 -m battle_skill.invariant_judge \
--judge fixtures/reference-judges/no_data_leak_judge.py \
--target <released-output-dir> \
--params '{"policy": "policy.json", "output_subdir": "corpus"}'
fixtures/reference-judges/no_data_leak_judge.py is the anonymizer
confidentiality invariant as a Judge: it independently scans released output
(JSON scalars incl decoded escapes, numeric expansion, SQLite cells + schema
DDL + header integers, text/CSV, report.json, and captured stdout/stderr) for
any policy value in any representation.
Battle is not project-specific. For any project or skill with an
acceptance_contract.bundle.v1, Battle should expand each contract item through
Dogpile before claiming comprehensive adversarial coverage:
./run.sh contract-variation-plan \
--acceptance-bundle /path/to/acceptance_bundle.json \
--dogpile-source brave-search \
--dogpile-source arxiv \
--out /tmp/battle-variation-plan.json
The output is battle.contract_variation_plan.v1. It is a three-phase Battle
contract, not a loose note:
acceptance_contract.bundle.v1 floor.$project-state, current Battle receipts,
source-filtered $dogpile research, and $ask one-shot reviewer proposals.The plan maps every acceptance case to source-bearing Dogpile research lanes and
reusable variation families. Use repeatable --dogpile-source filters when a
Battle phase needs only selected Dogpile providers such as brave-search,
arxiv, github-search, youtube, brave-questions, feeds, wayback, or
context7 instead of the full source fanout. The reusable variation families
include representation equivalence, encoding/normalization, parser differentials,
release-surface boundaries, lossy conversion, split/composed facts, scale,
retry/concurrency, authorization, and failure-leak boundaries. Dogpile and Ask
are research input only: they discover meaningful variation families and source
evidence. Battle then freezes selected families into deterministic generators,
runs the real target in Docker/QEMU/digital-twin evidence gates, emits
battle.case_receipt.v1 per case, aggregates with battle.campaign_aggregate.v1,
and retains the workflow classes as $agentic-evals cases. A serious release
gate should expect hundreds of deterministic cases and roughly 20-30 retained
eval classes when the contract surface is broad; smaller smoke gates must label
themselves as smoke.
An invariant battle judges one output. An invariant campaign has Red generate
the whole MATRIX of input "versions" the target's spec names -- every format x
every representation x the documented edge cases -- PLUS random fuzz, runs the
real target on each, and the Judge scores every output. Every case emits a
battle.case_receipt.v1 with fixture precheck, execution, rejection, security
Judge, optional functional Judge, and verdict fields. A campaign PASSES only if
all case receipts pass, required MUST_ACCEPT cases are actually accepted and
functionally judged, required MUST_REJECT cases are safely rejected, and the
computed battle.campaign_aggregate.v1 has no failed or incomplete cases. One
failing version is a concrete, reproducible Red win.
For anonymization/privacy targets, the acceptance contract is only the floor.
When an acceptance_contract.bundle.v1 exists, the arena build may pass it as
acceptance_floor to the production adapter. Battle then fails closed unless
every acceptance_cases[] id maps to at least one campaign generator case in the
profile's required_case_ids; those are the bare-minimum adversarial versions
that MUST pass before any extra fuzz or beyond-contract cases matter. Battle must
also run a beyond-contract campaign that attacks surfaces a client brief often
omits: JSON keys and duplicate keys, CSV headers/dialects/multiline cells,
SQLite identifiers/defaults/generated values/partial indexes/triggers,
filenames, report.json, stdout/stderr, alternate encodings, and same-identity
representation traps. A clean brief-matrix replay alone is a smoke proof, not a
comprehensive Battle proof.
python3 -m battle_skill.invariant_campaign \
--generator fixtures/reference-generators/anon_brief_matrix.py \
--target-run-cmd 'docker run --rm -v {input}/corpus:/trial/input/corpus:ro -v {input}/policy.json:/trial/input/policy.json:ro -v {output}:/trial/output anonymization-trial run' \
--judge fixtures/reference-judges/no_data_leak_judge.py \
--gen-params '{"fuzz": 20}' --judge-params '{"output_subdir": "corpus"}'
fixtures/reference-generators/anon_brief_matrix.py yields the anonymization
brief's versions: the four formats, JSON string/int/float/scientific, SQLite
TEXT/INTEGER/REAL, Unicode NFC/NFD, BOM, JSON \u-escape, SQLite CHECK-literal,
plus fuzz. It also carries the oai-trial roundtable edge cases: formatted policy
phone values stored as digit-only JSON/SQLite numerics, the same identity seeded
across every in-scope format, and lossy leading-zero / large-float traps.
fixtures/reference-generators/anon_beyond_brief_matrix.py is the required next
rung for privacy/anonymization proof: it tries non-obvious schema/path/encoding/
log/release-boundary surfaces that go beyond the literal acceptance contract. A
generator + target-run-cmd + judge is a pluggable trio: point it at any project's
spec matrix and invariant.
The no-data-leak Judge also supports an explicit opt-in interpretation profile
for transformation semantics. These guarantees are OFF unless declared in
--judge-params, so Battle does not silently expand the contract after seeing a
failure:
{
"interpretation_profile": {
"decoders": ["base64", "base64url", "hex"],
"record_local_reconstruction": true,
"max_decoded_bytes": 4096
}
}
With that profile, whole scalar/token base64/base64url/hex values are decoded once and record-local adjacent JSON/CSV/SQLite scalar fields may reconstruct a complete policy value. Arbitrary recursive decoding, global field joins, and visual-confusable character folding remain out of the default blocking gate.
After Red finds failing cases and Blue patches the target, emit the replayable lineage receipt instead of summarizing in prose:
./run.sh invariant-lineage-receipt \
--red-campaign /tmp/red-result.json \
--replay-campaign /tmp/replay-result.json \
--target oai-trial \
--out /tmp/battle-lineage.json
A battle.invariant_adaptive_lineage.v1 PASS proves Red found contract edge
cases, Blue removed those Red wins, and the independent Judge replay passed.
Then Battle must produce a $create-report-validated report with $project-state
context and an explicit exploits table. The report is the human-readable decision
artifact; receipts remain the authority. Generate fresh project state first,
then render the report:
PROJECT_STATE_ROOT=/path/to/target ../project-state/run.sh report --json --output /tmp/project-state.json
./run.sh invariant-report \
--campaign /tmp/battle-brief-fuzz.json \
--campaign /tmp/battle-beyond-brief.json \
--adaptive-lineage /tmp/battle-lineage.json \
--project-state /tmp/project-state.json \
--target oai-trial \
--out-json /tmp/battle-report.json \
--out-md /tmp/battle-report.md
For project-agent terminal review, use cards when cases have long evidence:
./run.sh invariant-report \
--campaign /tmp/battle-brief-fuzz.json \
--campaign /tmp/battle-beyond-brief.json \
--project-state /tmp/project-state.json \
--target oai-trial \
--out-json /tmp/battle-report.json \
--out-md /tmp/battle-report.md \
--terminal-cards
invariant-report is a Typer CLI command. It writes machine JSON to stdout and
keeps the human Battle report on stderr. Use --terminal-cards for normal
project-agent review of Battle evidence: it groups cards under Acceptance contract floor, Beyond-contract exploits, Adaptive lineage, and fallback
Other campaign cases headings, then prints one ============== block per case
with Scope, Case, Acceptance parent, Expect, Result, Example, Why Battle checks this, Related research, Adaptive lineage, and Judge evidence. If a production-adapter receipt carries acceptance_floor.case_map,
contract-floor cards show the parent AC-* id(s); otherwise Acceptance parent
is not recorded in case receipt. If a receipt has example, why_chosen,
research_refs, or source_refs, cards show those exact fields; otherwise
examples/rationales are deterministic from the case id and research is reported
as not recorded in case receipt.
--terminal-table remains the compact overview alias for --terminal-summary:
both print contract floor, Red pressure, Scorekeeper call, and one case-table row
per attack. In an interactive terminal Battle uses Rich's terminal-aware colored
table (RED_WIN red, clean passes green, fail-closed stops yellow) and honors
NO_COLOR; under capture/CI it falls back to deterministic plain text so logs
and tests stay stable.
invariant-report writes create_report.report.v1, validates it through
skills/create-report/run.sh validate, renders Markdown through
skills/create-report/run.sh render, and appends ## Exploits Table. The table
must be plain-spoken and scannable: one row per attack case, with columns for
Scope, Contractual?, Adaptive lineage?, Case, Exploit / attack,
Why chosen, Expectation, Result, and Judge evidence. Scope separates
contractual acceptance-floor cases from beyond-contract probes;
Why chosen explains non-contractual probes; Adaptive lineage? marks Red wins
that were fixed and replayed; RED_WIN blocks release. The table is derived
from battle.case_receipt.v1 when present, falling back to legacy case_log
only for older campaign receipts. A Battle closure without that report is
missing the decision surface even if campaign receipts pass.
Battle's purpose is the Red/Blue security competition backend: authorized target setup, isolated execution, Red attack generation, Blue defense generation, independent Judge replay, scorekeeper receipts, adaptive lineage, and durable learning. Adaptive lineage is a backend learning loop that spawns, evaluates, selects, and promotes or rejects child Red/Blue evidence from Judge-backed receipts.
PixiJS is only a spectator/replay surface for Battle receipts. A PixiJS pass proves that recorded receipts can be inspected in a fun replay; it does not prove the Battle orchestrator, provider-driven subagents, Docker/QEMU isolation, overnight scheduler, scorekeeper, or memory learning works. Do not close core Battle readiness from PixiJS evidence alone, and do not block backend adaptive lineage on replay polish beyond truthful receipt inspectability.
Production Battle is an orchestration skill, not a large bespoke security engine. The host-side process should schedule rounds, choose personas, dispatch subagents, provision Docker runtimes, collect receipts, score hard runtime signals, write reports, and persist learning. Target code and team-generated code must execute only inside Docker.
Required production invariants:
security.target_authorization.v1 manifest before
Docker, QEMU, target runtime setup, Hack delegation, proof replay, or patch
replay starts. The manifest binds project/operator scope and target identity;
it is not a legal opinion and does not prove exploit success or patch
effectiveness.$hack execution is a subagent responsibility, not a Battle Python
import. Battle performs or schedules scan/research/memory recall, builds the
candidate exploit list, chooses the Red persona, dispatches an
agent-skills/agents/Tau subagent with that contract, and records the
returned exploit receipt.tau.agent_handoff.v1 and tau.subagent_receipt.v1,
with Battle-specific fields layered on top rather than a separate ad hoc
protocol.scillm as the LLM/model caller. Battle owns
team selection, persona assignment, Docker runtimes, scorekeeping, artifacts,
and memory promotion.$scillm, /scillm, http://localhost:4001,
/v1/chat/completions, or /v1/scillm/* directly for Battle proof work.
Express provider work as Tau DAGs, Tau command-loop nodes, or Tau skill nodes,
then consume Tau receipts and node outputs.dogpile, brave-search, memory, GitHub/code search,
docs, papers, CVEs, and public writeups.$memory.brave-search and dogpile calls, including 10x concurrent Brave
search batches when needed, then store useful results and negative evidence in
$memory.$github-search
evaluation criteria first. Any adopted repo code, PoC, scanner, or payload
still runs only inside Battle's isolated target/runtime gates; do not execute
untrusted repo-provided install scripts or payloads on the host.Based on research into RvB framework, DARPA AIxCC, and Microsoft PyRIT:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Battle Orchestrator β
β - Game loop (RvB pattern) β
β - Concurrent Red/Blue execution β
β - Entropy-driven termination β
β - Checkpointing for overnight runs β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
ββββββ΄βββββ ββββββ΄βββββ
β Red Team β β Blue Teamβ
β (Thread) β β (Thread) β
ββββββββββββ€ ββββββββββββ€
β Skills: β β Skills: β
β - hack β β - anvil β
β - memory β β - memory β
ββββββββββββ ββββββββββββ
β β
ββββββββββββ¬ββββββββββββββββββββ
β
βββββββββββββββββ΄βββββββββββββββββββββ
β Digital Twin β
β βββββββββββββββββββββββββββββββ β
β β Mode: git_worktree β β
β β - Red attacks arena β β
β β - Blue patches workspace β β
β β - Cherry-pick to test β β
β βββββββββββββββββββββββββββββββ€ β
β β Mode: docker β β
β β - Isolated containers β β
β β - Battle network β β
β βββββββββββββββββββββββββββββββ€ β
β β Mode: qemu β β
β β - Emulated firmware β β
β β - GDB attach points β β
β βββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββ
The battle skill supports multiple target types through its Digital Twin system:
For battling over git repositories. Creates isolated git worktrees for each team.
./run.sh battle /path/to/repo --rounds 100
For battling over containerized applications. Spins up separate containers for each team.
# Using a Docker image
./run.sh battle --docker-image nginx:latest --rounds 100
# Using a Dockerfile in the target directory
./run.sh battle /path/with/Dockerfile --mode docker
For battling over firmware and embedded systems. Boots firmware in QEMU emulator.
# Auto-detect architecture from ELF header
./run.sh battle firmware.elf --rounds 100
# Specify machine type explicitly
./run.sh battle firmware.bin --qemu-machine arm
./run.sh battle firmware.bin --qemu-machine riscv64
./run.sh battle bios.rom --qemu-machine x86_64
Supported QEMU machines:
arm - ARM Cortex-M (STM32, etc.)aarch64 - ARM64riscv32/riscv64 - RISC-Vx86_64/i386 - x86mips - MIPS (routers, embedded)For battling over host-level policy (systemd units, AppArmor profiles, cgroup-BPF IP
filters) that Docker twins cannot host because containers share the host kernel.
Boots a base cloud image (e.g. Ubuntu 24.04 qcow2) with a fresh overlay per round,
KVM acceleration, ephemeral SSH key via NoCloud cloud-init, executes one payload
inside the VM, and writes a battle.vm_round.v1 receipt. Requires a
security.target_authorization.v1 manifest binding the image path AND sha256
before QEMU starts.
./run.sh vm-round --image /mnt/storage12tb/skills/battle/images/noble-server-cloudimg-amd64.img \
--command 'uname -r; echo VM_CANARY_OK' \
--authorization-manifest fixtures/vm-round/authorization.json --out-dir /tmp/battle-vm
Snapshot discipline: each round boots base.qcow2 + throwaway overlay (qemu-img
backing file), so rounds never accumulate state; persistent learning belongs in
$memory, not the disk image.
For non-git directories. Creates simple file copies for each team.
# Start a battle (10 rounds for testing)
./run.sh battle /path/to/codebase --rounds 10
# Start overnight battle (1000 rounds)
./run.sh battle /path/to/codebase --overnight
# Battle a Docker container
./run.sh battle --docker-image myapp:latest --rounds 100
# Battle firmware with QEMU
./run.sh battle firmware.bin --qemu-machine arm --rounds 100
# Check battle status
./run.sh status
# Resume interrupted battle
./run.sh resume <battle-id>
# Generate report from completed battle
./run.sh report <battle-id>
# Run the deterministic Battle v0 fixture proof
./run.sh battle-fixture battle-001 --out /tmp/battle-001
# Run the reactive Blue + independent Judge Docker proof
./run.sh prove-reactive-judge-round \
--authorization-manifest skills/battle/fixtures/reactive-judge/authorization.json \
--out /tmp/battle-reactive-judge-round
# Run canonical BATTLE-004 with parent-spawn lineage requested
./run.sh arena-parent-spawn-proof battle-004 --out /tmp/battle-004-parent-spawn --red-workers 2 --blue-workers 2
Battle v0 is a narrow, deterministic proof rung for the Battle artifact contract. It runs one local Red -> Blue -> Judge fixture and emits replayable receipts:
red-receipt.jsonblue-receipt.jsonjudge/judge-receipt.jsonscoreboard.jsonmonitor-index.jsonrun-receipt.jsonThe Battle v0 scoreboard is derived from the independent Judge receipt, not from
Blue-side self-certification fields. This addresses the current battle loop gap
where a Blue patch can carry verified and functionality_preserved claims
without a separate Judge phase.
The fixture proof is intentionally limited:
mocked: no
live: local_deterministic_fixture
agentic: false
models_used: []
It proves the receipt boundary and monitor artifact rendering for the local
fixture only. It does not prove real Red or Blue agent behavior, scillm,
OpenCode, anvil, code-runner, memory learning, Docker, QEMU, or multi-round
campaign readiness. See docs/BATTLE_V0.md for the validation commands and
artifact-backed monitor proof path.
prove-reactive-judge-round is the deterministic local Docker proof rung for
the default Battle round authority boundary. It runs a small authorized fixture
with one command-injection behavior and one candidate patch:
mocked: no
live: local_docker_fixture
agentic: false
models_used: []
The proof emits:
authorization-validation.jsonimmutable-baseline-manifest.jsonevent-ledger.jsonred-hack-observation.jsonjudge-1/judge-1-receipt.jsonblue/proactive-blue-input.jsonblue/reactive-blue-input.jsonblue/candidate-patch-receipt.jsonjudge-2/judge-2-receipt.jsonscorekeeper-receipt.jsonround-receipt.jsonartifact-hash-manifest.jsonThe required phase order is authorization, immutable baseline, concurrent Red
and proactive Blue, Red observation, Judge #1 confirmation, reactive Blue,
candidate patch, Judge #2 replay, scorekeeper, and round receipt. Proactive Blue
must receive no private Red finding. Reactive Blue may receive only the
Judge-confirmed finding and replay contract. The scorekeeper derives Red/Blue
scores only from Judge receipts; Blue verified, success, and
functionality_preserved fields are advisory and not score authority.
The ordinary in-process battle round now fails closed at this same authority
boundary: it preserves proactive overlap, dispatches reactive Blue only for
Judge-confirmed findings, and does not award Blue score without a Judge #2
success verdict. The local Docker proof is the executable receipt path for the
complete reactive/Judge behavior. It does not prove provider-driven Red/Blue
quality, arbitrary target exploitability, production deployment readiness, or
overnight scheduler readiness.
| Metric | Weight | Description |
|---|---|---|
| Vulnerability Discovery | 1x | Red team finds vulnerability |
| Exploit Proof | +0.5x | Red team proves exploitability |
| Successful Patch | 3x | Blue team patches vulnerability |
| Time Decay | Variable | Faster responses score higher |
| Functionality Preserved | Required | Patches must not break code |
Each round follows a learn β act β reflect pattern:
Round k:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 1. RESEARCH PHASE β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Red Team: Blue Team: β
β - Recall past attack attempts - Recall past defenses β
β - Query /dogpile for new - Query /dogpile for β
β exploitation techniques hardening strategies β
β - Review opponent's patterns - Analyze attack evolution β
β (Budget: 3 research calls max) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 2. ACTION PHASE β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Red Team Attack: Blue Team Defense: β
β - Execute learned strategy - Apply patches via anvil β
β - AFL++ fuzzing with coverage - Verify via QCOW2 overlay β
β - Collect crashes/findings - Run regression tests β
β - Tag findings with /taxonomy - Tag patches with /taxonomy β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 3. REFLECTION PHASE β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Both Teams: β
β - Archive round episode (actions, outcomes, learnings) β
β - Store successful strategies in /memory β
β - Update belief about opponent's capabilities β
β - Evolve strategy for next round β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 4. SCORING & CHECKPOINT β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β - Calculate AIxCC-style scores β
β - Check termination conditions β
β - Save checkpoint (QEMU state + team memories) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Each team maintains isolated knowledge:
battle_red_<battle_id>/ battle_blue_<battle_id>/
βββ strategies/ βββ strategies/
β βββ successful_attacks β βββ successful_patches
β βββ failed_attempts β βββ broken_defenses
βββ research/ βββ research/
β βββ dogpile_results β βββ dogpile_results
βββ episodes/ βββ episodes/
β βββ round_001.json β βββ round_001.json
β βββ round_002.json β βββ round_002.json
βββ taxonomy/ βββ taxonomy/
βββ cwe_classifications βββ mitigation_types
βββ severity_scores βββ effectiveness_scores
Teams cannot access opponent's memory - this creates true adversarial learning.
Battle ends when ANY condition is met:
./run.sh stopBattles register with task-monitor for overnight progress tracking:
# View battle progress in TUI
.pi/skills/task-monitor/run.sh tui --filter battle
After battle completion, generates:
The skill integrates with the shared memory and taxonomy systems via
memory_integration.py for cross-battle learning:
recall_prior_battles): Before starting a battle, recalls prior
battle findings for the same target or technique. Enables teams to build on
accumulated security knowledge across battles.learn_battle): After battle completes, stores the full outcome
(target, red findings, blue defenses, winner, scores, TDSR) to memory with
taxonomy bridge tags.["battle", "security"] + bridgesGracefully degrades if common.memory_client or taxonomy/taxonomy.py are unavailable.
Battle Red agents may behave as nondeterministic exploit-code authors. A Red exploit subagent may combine high-level web, protocol, MITM, packet, timing, source-level, binary, assembly, fuzzing, and obscure research-derived techniques into generated exploit specimens.
Most generated specimens may be bad ideas: they may fail to compile, fail at runtime, combine irrelevant methods, or produce no useful target signal. Battle treats those outputs as genetic material, not proof.
Battle owns deterministic selection and evidence:
The first backend proof rung is exploit-combiner-proof. It is fixture-backed,
agentic:false, and proves the specimen lifecycle only: bad generated code,
Docker execution, captured failure observations, target contact, runnable
unproven code, and fail-closed non-claims. Live Tau generation, child
materialization, packet capture, Blue adaptation, memory promotion, and Judge
exploit-success replay are later rungs.
The second backend proof rung is spawn-architect-proof. It is fixture-backed,
agentic:false, and proves the DAG birth contract only: Battle loads a
spawn-policy decision, constructs a child knowledge packet from parent specimen
evidence, authors a tau.dag_contract.v1 child exploit-synthesis DAG, validates
private-artifact exclusions, and records that Tau execution is deferred to PR3.
It does not run Tau, materialize a child exploit, generate live exploit code,
compile child code, contact the target, or claim exploit success.
The current live Tau child DAG canary is live-tau-child-dag-canary. It is
non-mocked and invokes the existing local Tau DAG runtime without fixture
fallback. The PR3b/PR3c boundary is:
lineage-summarizer PASS
research-scout PASS with Tau-validated source-bearing design-input receipts
method-combiner PASS with a deterministic exploit genome candidate
exploit-code-author PASS only when Tau/SciLLM returns provider_live:true
provider-authorship evidence; otherwise BLOCKED at the precise attestation gap
The PR3c boundary may materialize provider-authored child exploit code, but it does not compile child code, run a child specimen in Docker, or claim exploit success. Compile repair, Docker execution, and Judge replay are later gates.
battle/
SKILL.md # This file
run.sh # Shell entry point; launches package through uv
sanity.sh # Deterministic fixture and structure sanity gate
pyproject.toml # Dependencies
.ask/browser-oracles.yaml # WebGPT project mapping for browser-oracle walk-up
src/battle_skill/
cli.py # Typer CLI entry point
config.py # Constants and paths
state.py # Data classes and BattleState
memory.py # Team-isolated memory system
scoring.py # AIxCC-style scoring
digital_twin.py # Git worktree, Docker, QEMU isolation
red_team.py # Red Team attack agent
blue_team.py # Blue Team defense agent
orchestrator.py # Game loop orchestrator
battle_fixture.py # Deterministic fixture proof runner
judge.py # Deterministic scorekeeper verifier
receipts.py # Receipt dataclasses and JSON writer
report.py # Report generation
qemu_support.py # QEMU emulator support
qemu_peripherals.py # QEMU peripheral emulation
fixtures/battle-001/ # Deterministic local fixture
spectator/ # Self-contained BATTLE-004 spectator UI + Pixi engine
monitor/battle/ # Artifact-backed React monitor
| Skill | Team | Purpose |
|---|---|---|
| hack | Red | Scanning, auditing, exploitation |
| anvil | Blue | Multi-agent patching (Thunderdome) |
| memory | Both | Recall prior strategies |
| treesitter | Blue | Code structure analysis |
| taxonomy | Both | Classify findings |
| task-monitor | Orchestrator | Progress tracking |
| ops-docker | Both | Container management |
# Start 100-round battle on current project
./run.sh battle --target . --rounds 100
# Output:
# Battle ID: battle_20250128_221500
# Target: /home/user/project
# Rounds: 100
#
# Registering with task-monitor...
# Starting Round 1/100...
# [Red] Scanning target with hack...
# [Red] Found 3 potential vulnerabilities
# [Blue] Analyzing attack logs...
# [Blue] Generating patch for SQL injection...
# [Blue] Patch applied, running verification...
# Round 1 complete. Red: 3 pts, Blue: 9 pts
# ...
#
# Battle Complete!
# Winner: Blue Team (847 pts vs 423 pts)
# Report: ./reports/battle_20250128_221500.md