Documentation Index
Fetch the complete documentation index at: https://mintlify.com/AdithyaaSivamal/Agentic-AFL/llms.txt
Use this file to discover all available pages before exploring further.
AgentLoop is the central orchestration daemon. It polls for AFL++ stalls, processes them through the full Extract→Translate→Solve→Inject pipeline, and manages the ReAct self-correction loop. Each stall is placed on a priority queue by severity and processed one at a time; successful solves are permanently suppressed so the agent never re-processes an already-solved address.
When used via CampaignRunner, AgentLoop is instantiated and managed automatically. You can also instantiate it directly for custom integrations that need finer control over stall processing, harvest mode, or signal handling.
Import
Constructor
AFL++ output directory (the
-o argument passed to afl-fuzz). The stall detector reads fuzzer_stats and the queue from subdirectories inside this path. Falls back to settings.afl_output_dir from the environment configuration if not provided.Sync directory for payload injection. Solved payloads are written here as
.bin files; AFL++ ingests them on its next cycle via the -F sync flag. Falls back to settings.afl_sync_dir if not provided.Path to the binary being fuzzed. Used by the GDB-based offset probe (
extract_arg_memory) to discover the base offset of the input buffer pointer and capture runtime register/memory state at the stall address. When None, GDB probing is skipped and the LLM relies solely on static P-Code and decompiled C.Force a specific hex address string (e.g.,
"0x08004210") as the stall site, bypassing the automatic stall detector entirely. Useful for unit tests, benchmarking, and targeted experiments against a known hard branch.Minimum number of AFL++ cycles at a plateau before the stall detector fires. Higher values reduce noise from transient slowdowns; lower values make the agent more responsive. Falls back to
settings.min_stall_cycles if None.Enable harvest mode. When
True, CARM template retrieval is disabled (forcing zero-shot LLM generation) and every successful solve is verified by measuring the AFL++ edge delta after injection. Verified solves are automatically committed back to the CARM corpus. Use this to build up a template library from scratch on a new target class.Register
SIGINT/SIGTERM handlers that call shutdown(). Set to False when the caller (e.g., CampaignRunner) manages signal handling itself, to prevent the agent’s handler from overwriting the caller’s.Methods
async setup() -> None
Initialize all sub-components. Must be called once before run(). Instantiates and configures:
- SpecStore — PostgreSQL connection for persisting
VulnerabilitySpecrecords - PCodeSlicer — Ghidra-backed P-Code backward slice extractor
- ConstraintProfiler — Structural constraint tag analyzer
- SpecExporter — Writes specs to PostgreSQL
- CARMRetriever — Cosine/Jaccard similarity search over the spec store
- LLMClient — Z3Py script generator (reads provider from
settings) - Z3Sandbox — Isolated subprocess executor for LLM-generated Z3 scripts
- StallDetector — Polls
fuzzer_statsand the AFL++ queue for coverage plateaus - PayloadInjector — Writes solved payloads to the sync directory
setup() establishes a live PostgreSQL connection via SpecStore.initialize(). Ensure settings.postgres_dsn is set correctly in your environment before calling it.async run() -> None
Main daemon loop. On each iteration the loop:
- Calls
StallDetector.detect()to collect new stall reports - Enqueues each new stall by
StallSeveritypriority (CRITICAL first) - Dequeues the highest-priority stall and processes it through the full pipeline
- Sleeps for
settings.stall_poll_intervalseconds before the next iteration
_running is set to False (via shutdown() or external assignment). When it exits, the PostgreSQL connection is closed and final metrics are logged.
get_metrics() -> dict
Return a snapshot of runtime metrics accumulated since run() started. See Runtime Metrics below for field descriptions.
async shutdown() -> None
Gracefully stop the daemon loop by setting _running = False. The loop will complete its current iteration (including any in-flight stall processing) before exiting. The PostgreSQL connection is closed as part of the exit sequence.
Runtime Metrics
get_metrics() returns a dict with the following fields:
Total stall reports enqueued since
run() started. Includes stalls that were later skipped because the address was already solved.Total stall reports that completed the full pipeline (whether or not they resulted in a SAT solve).
Total payloads successfully written to the AFL++ sync directory. Includes both primary solves and diversity-generator variants.
Total ReAct loop iterations consumed across all processed stalls. Each turn generates K Z3 scripts and executes them in the sandbox.
Total LLM API calls made. One call per ReAct turn (each call generates K candidate scripts in parallel).
Current number of stalls waiting in the priority queue (not yet dequeued for processing).
Number of stalls currently being processed concurrently. Under the current single-consumer design this is always 0 or 1.
(Harvest mode only) Solves that were confirmed by a positive edge delta after injection.
(Harvest mode only) Verified solves committed back to the CARM template corpus.
Usage: CampaignRunner vs Standalone
AgentLoop is used internally by CampaignRunner, which handles setup, signal registration, and AFL++ process management for you. Use AgentLoop directly when you need:
- Integration with an existing AFL++ deployment not started by
CampaignRunner - Harvest mode for template corpus building
- Custom stall address overrides for benchmarking
- Fine-grained access to per-stall metrics