rotalabs-redqueen
Quality-diversity evolutionary red-teaming for LLMs and agents, from Rotalabs.
Rather than hand-crafting jailbreaks, rotalabs-redqueen evolves diverse, effective attack strategies and maps the vulnerability space with MAP-Elites. It operates at the semantic level and spans the full 2026 attack surface:
- Single-turn prompt attacks (strategies, encodings, personas)
- Multi-turn Crescendo-style escalation
- Agentic / tool-use / MCP multi-step exploit plans
Seeded runs are bit-reproducible (and cross-language portable), and a campaign can be projected into an audit-ready compliance report (OWASP, MITRE ATLAS, EU AI Act Art. 55, NIST AI RMF).
2.0 is a breaking release. See
CHANGELOG.mdfor migration from 1.x.
Installation
pip install rotalabs-redqueen # core + mock target
pip install rotalabs-redqueen[openai] # + OpenAI
pip install rotalabs-redqueen[anthropic]
pip install rotalabs-redqueen[llm] # all providers
pip install rotalabs-redqueen[dev] # tests/lint
Quick start
import asyncio
from rotalabs_redqueen import (
LLMAttackGenome, JailbreakFitness, MockTarget, HeuristicJudge, evolve,
)
async def main():
target = MockTarget() # swap for OpenAITarget / AnthropicTarget / GeminiTarget / OllamaTarget
fitness = JailbreakFitness(target, HeuristicJudge())
result = await evolve(
genome_class=LLMAttackGenome,
fitness=fitness,
generations=50,
population_size=20,
seed=1234, # same seed -> same result, every time
progress=False,
)
if result.best:
print("fitness:", result.best.fitness.value)
print("prompt:", result.best.genome.to_prompt())
asyncio.run(main())
Multi-turn and agentic attacks
The genome's phenotype is a Stimulus — a single prompt, a conversation, or an agentic action
plan — so the same engine drives every surface. Just swap the genome class:
from rotalabs_redqueen import MultiTurnGenome, AgenticGenome, JailbreakFitness, MockTarget, evolve
# Crescendo-style multi-turn escalation
mt = await evolve(genome_class=MultiTurnGenome,
fitness=JailbreakFitness(MockTarget()),
generations=50, population_size=20, seed=1, progress=False)
# Multi-step tool-use / MCP exploit plans
ag = await evolve(genome_class=AgenticGenome,
fitness=JailbreakFitness(MockTarget()),
generations=50, population_size=20, seed=1, progress=False)
To drive a real MCP server instead of the deterministic MockTarget, use MCPTarget — it
performs the MCP handshake and executes each agentic step as a tools/call, surfacing tool output
for judging:
from rotalabs_redqueen.llm import MCPTarget
target = MCPTarget(command=["npx", "-y", "@modelcontextprotocol/server-everything"])
# agentic action-plan steps become MCP tool calls; the tool output is what the judge scores
Quality-diversity with MAP-Elites
from rotalabs_redqueen import (
LLMAttackGenome, JailbreakFitness, MockTarget,
MapElitesArchive, BehaviorDimension, AttackStrategy, Encoding, evolve,
)
archive = MapElitesArchive(dimensions=[
BehaviorDimension("strategy", 0.0, 1.0, len(AttackStrategy)),
BehaviorDimension("encoding", 0.0, 1.0, len(Encoding)),
BehaviorDimension("has_persona", 0.0, 1.0, 2),
])
result = await evolve(genome_class=LLMAttackGenome,
fitness=JailbreakFitness(MockTarget()),
generations=100, archive=archive, seed=1, progress=False)
cov = result.archive.coverage()
print(f"coverage: {cov.coverage_percent:.1f}% ({cov.filled_cells} diverse attacks)")
Compliance report
Project the archive over the attack taxonomy into standards-aligned evidence:
from rotalabs_redqueen import ReportExporter
exporter = ReportExporter()
report = exporter.export(result.archive.get_all(),
campaign_id="run-1",
coverage=result.archive.coverage())
print(exporter.render(report, "markdown").decode()) # or "json"
The report groups successful attacks by harm category and crosswalks them to OWASP LLM/Agentic Top-10, MITRE ATLAS, EU AI Act Article 55, and NIST AI RMF GOVERN 1.7.
Co-evolution (attacker vs defender)
Evolve an attacker population against a defender population — defenders evolve guardrails that reduce attack success, attackers adapt to bypass them:
from rotalabs_redqueen import (
coevolve, LLMAttackGenome, SystemPromptDefense,
JailbreakFitness, DefenderBlockFitness, MockTarget, HeuristicJudge,
)
base, judge = MockTarget(), HeuristicJudge()
result = await coevolve(
attacker_class=LLMAttackGenome,
defender_class=SystemPromptDefense,
attacker_fitness_vs=lambda d: JailbreakFitness(d.as_defense(base), judge),
defender_fitness_vs=lambda a: DefenderBlockFitness(a, base, judge),
generations=20, population_size=24, seed=1,
)
print(result.best_defender.to_dict(), result.attacker_fitness, result.defender_fitness)
Persistence and continuous red-teaming
Archives serialize, so attacks accumulate across runs (e.g. a CI gate that gets stronger over time):
from rotalabs_redqueen import MapElitesArchive, LLMAttackGenome, Rng
result.archive.save("file://archive.json")
prior = MapElitesArchive.load("file://archive.json", LLMAttackGenome)
warm_start = prior.seed(10, Rng(0)) # sample elite genomes to seed the next run
Command line
rotalabs-redqueen run --target mock:random --generations 20 --seed 1
rotalabs-redqueen run --target openai:gpt-4 --use-archive --output results.json
rotalabs-redqueen run --target mock:random --llm-judge anthropic:claude-sonnet-4-20250514
rotalabs-redqueen info --strategies | --encodings | --targets
Architecture
Core framework (generic, reusable for any QD problem): Genome, Fitness, Population,
Selection (tournament / novelty / lexicase), MapElitesArchive, Evolution, and the
canonical Rng.
LLM domain: LLMAttackGenome / MultiTurnGenome / AgenticGenome; targets — OpenAI,
Anthropic, Gemini, Ollama, Mock, and MCPTarget (drives a real MCP server over stdio);
Judge (heuristic, LLM); JailbreakFitness / MultiTargetFitness; co-evolution (coevolve,
SystemPromptDefense, DefenderBlockFitness).
| Surface | Genome | Stimulus kind |
|---|---|---|
| Single-turn | LLMAttackGenome |
single_turn |
| Multi-turn | MultiTurnGenome |
multi_turn |
| Agentic / MCP | AgenticGenome |
agentic |
Extending
Custom genome
from rotalabs_redqueen import Genome, BehaviorDescriptor, Stimulus
class MyGenome(Genome["MyGenome"]):
@classmethod
def random(cls, rng): ...
def mutate(self, rng): ...
def crossover(self, other, rng): ...
def to_stimulus(self) -> Stimulus:
return Stimulus.single_turn(prompt="...")
def behavior(self) -> BehaviorDescriptor: ...
def distance(self, other) -> float: ...
def to_dict(self) -> dict: ...
@classmethod
def from_dict(cls, data) -> "MyGenome": ...
rng is the canonical Rng — use rng.random(), rng.integers(n), rng.choice(n, size, replace=False),
rng.shuffle(list) so runs stay reproducible.
Custom target
from rotalabs_redqueen import LLMTarget, Message, TargetResponse
class MyTarget(LLMTarget):
@property
def name(self) -> str:
return "my-target"
async def _complete(self, messages: list[Message]) -> TargetResponse:
text = await my_llm_api([{"role": m.role, "content": m.content} for m in messages])
return TargetResponse(content=text, model="my-model")
interact() (single-turn + scripted multi-turn rollout) is provided by the base class.
Custom judge
from rotalabs_redqueen import Judge, JudgeResult
class MyJudge(Judge):
async def judge(self, stimulus, transcript) -> JudgeResult:
score = my_score(transcript.assistant_text)
return JudgeResult(success=score >= 0.5, score=score)
Reproducibility & conformance
Seeded campaigns are deterministic and cross-language portable: the canonical PRNG (xoshiro256++ + SplitMix64) is cross-validated against an independent implementation, and an L1–L5 conformance suite gates engine, LLM-domain, report, multi-turn/agentic, and co-evolution behavior against golden fixtures, all reproduced byte-for-byte by the TypeScript package.
pytest # full suite incl. conformance
python -m rotalabs_redqueen._gen_conformance # regenerate golden fixtures (intentional changes only)
Use cases
Red-teaming, guardrail/defense testing, robustness benchmarking, and documented adversarial-testing evidence for compliance.
Responsible use
For defensive security research — testing systems you own or are authorized to test. Do not use it to attack systems without authorization or to circumvent the safety of production systems.
Links
- Website: https://rotalabs.ai
- GitHub: https://github.com/rotalabs/rotalabs-redqueen
- Documentation: https://rotalabs.github.io/rotalabs-redqueen/
- Contact: research@rotalabs.ai
Metadata
Release files for rotalabs-redqueen 2.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| rotalabs_redqueen-2.0.0.tar.gz | 206.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| rotalabs_redqueen-2.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 272.9 kB
Release files / rotalabs_redqueen-2.0.0.tar.gz
| Download URL | rotalabs_redqueen-2.0.0.tar.gz |
|---|---|
| Size | 206.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a041891a5d07f1a9f518de71b21352869c094b323af867b4114179c9715514b5
|
|
BLAKE2b-256 checksum How to use checksums |
2b218200d735a4ee01cdda080cb8a1e1efabe79a7eb1b96a3229e12884dbc9b1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.6
|
Release files / rotalabs_redqueen-2.0.0-py3-none-any.whl
| Download URL | rotalabs_redqueen-2.0.0-py3-none-any.whl |
|---|---|
| Size | 66.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
49b70f638cd24dada337928a72d330d04e881c3929995f492f2919a9dc78cb61
|
|
BLAKE2b-256 checksum How to use checksums |
6fe7551e1356218df3977fad3a82d22edd306df9fdbb5c8707867353247adb65
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.6
|