← Discover MCPs and Agents
f
AgentAI & MLGitHub

fackel

🔥 OSINT (Open Source Intelligence) analysis tool that uses the power of an autonomous AI agent

Links

README

From the repo.

Fackel

Fackel logo

Autonomous pentest framework powered by ReAct agents.
LLM-driven reconnaissance, scanning, triage, and report generation.

Python 3.12+ License: Apache 2.0 LangGraph

The interactive harness — parallel agent lanes, a live pipeline stepper, and inline approval gates.


What is Fackel?

Fackel is a multi-agent pentest framework where LLMs decide what to do, not hardcoded pipelines. Each specialist agent uses the ReAct pattern (Reason + Act) to autonomously choose which tools to call, interpret results, and decide next steps.

Target → OSINT → Approval Gate → Port Scan → Vuln Scan → Triage → Report
           ↕          ↕              ↕            ↕          ↕        ↕
       27 tools  Human-in-     2 tools      12 tools   LLM-as-   LLM
       (passive)  the-Loop      (active)     (active)   a-judge  synthesis

Key features

FeatureDescription
Real ReAct agentsEach specialist is a create_agent with its own system prompt, tools, and LLM. The model decides strategy, not code.
5-phase pipelineOSINT → Port Scan → Vulnerability Scan → Triage → Report. Each phase builds on the previous.
Human-in-the-loopAn approval gate pauses before active scanning, showing discovered targets for operator review.
LLM-as-a-judgeA quality evaluator scores each phase and drives adaptive routing — skip empty phases, adjust strategy for partial results.
Real-time observabilityWatch tool calls, results, errors, and LLM reasoning stream to the terminal as they happen.
Input validation railsEvery tool validates its inputs (target type, shell metacharacters) via guard_target() — raises ToolException for code-level enforcement, not just prompt instructions.
Resilient tool executionToolException + handle_tool_error propagate clean errors to the LLM. Circuit breakers disable flaky HTTP services after repeated failures. Configurable per-tool timeouts via environment variables.
Per-agent model configAssign different models to different agents via environment variables.
Automatic provider gatingTools requiring API keys are auto-removed when keys are missing, preventing wasted LLM calls.
Two-tier promptingShared soul prompt (identity + anti-hallucination rules) + task-specific skill prompts per phase.
Dual reportsConcise LLM report on console + comprehensive archival report saved to disk.
LangSmith tracingSet two env vars and all agent phases appear as hierarchical traces — token usage, tool I/O, latency, middleware activity.

Quick start

Requirements

RequirementNotes
Python 3.12+Required
uv or pipPackage manager
OpenAI API keyOr any compatible provider (Azure, Anthropic via LangChain)
Go ≥ 1.21For most scanning binaries (optional — only needed for active scanning)
Ruby (gem)For wpscan, whatweb (optional)
naabu, nmapFor port scanning (active scan)
nuclei, httpx, katana, subfinderFor vulnerability scanning (optional)

See docs/tools.md for the full list of required binaries per tool.

Automated tool install

# Install all external binaries automatically
./scripts/install-tools.sh

# Core tools only (nmap, naabu, nuclei, httpx, subfinder)
./scripts/install-tools.sh --minimal

# Audit — check which tools are installed/missing
./scripts/install-tools.sh --check

Install

# Clone and install
git clone https://github.com/flaviomilan/fackel.git
cd fackel
uv sync --python 3.12

Or with pip:

python -m venv .venv && source .venv/bin/activate
pip install -e .

Configure

cp .env.example .env
# Edit .env — OPENAI_API_KEY is the only required key

Run

Interactive harness (recommended)

Run fackel with no arguments to launch the interactive harness — a REPL around the agent pipeline with parallel agent lanes, inline approvals, and a knowledge graph you can query (shown in the demo above):

fackel
CommandWhat it does
/scan <target> [--no-active] [--approve-tools]Run a scan
/ask <question>Ask a natural-language question about the last scan's knowledge graph
/scansList persisted scans
/diff <old> <new>Diff two scans — new / resolved / changed assets
/graph [scan_id]Export the knowledge graph (Mermaid)
/context · /compactInspect the live context meter · summarise prior findings into session memory
/agents · /help · /quitList specialist agents · show help · exit

Tip: the harness renders with Nerd Font glyphs. No patched font? Set FACKEL_NERD_FONT=0 for an alignment-safe ASCII fallback.

One-shot scan

For CI or scripted runs, drive a single scan straight from the shell:

# Passive scan (OSINT only → report)
fackel scan example.com --no-active-scan

# Full scan (OSINT → port scan → vuln scan → triage → report)
fackel scan example.com

# Verbose mode — see LLM reasoning in real time
fackel scan example.com -v

# Save report to a specific file
fackel scan example.com -o report.md

# Check which provider API keys are configured
fackel scan example.com --check-providers --no-active-scan

Monitor changes across scans

# List persisted scans (requires the persistence store / data dir)
fackel scans

# Diff two scans — new / resolved / changed assets and findings
fackel diff <baseline-scan-id> <current-scan-id>

Pipeline overview

                     ┌─────────────────┐
                     │   osint_node    │ ← 27 passive tools
                     │  (ReAct agent)  │   dns, whois, subdomains, etc.
                     └────────┬────────┘
                              │
                    ┌─────────▼──────────┐
                    │  route_after_osint │
                    │  (conditional)     │
                    └──┬─────────────┬───┘
                       │             │
          active_scan  │             │  no active scan
          + IPs found  │             │  or no IPs
                       ▼             │
              ┌─────────────────┐    │
              │ approval_gate   │    │
              │ (HitL interrupt)│    │
              └───┬────────┬────┘    │
          approve │        │ reject  │
                  ▼        └────┐    │
           ┌────────────┐       │    │
           │ port_scan   │      │    │
           │ (ReAct)     │      │    │
           └─────┬───────┘      │    │
                 │              │    │
       ┌─────────▼───────────┐  │    │
       │route_after_port_scan│  │    │
       │(LLM-as-a-judge)     │  │    │
       └──┬──────────────┬───┘  │    │
          │              │      │    │
          ▼              ▼      │    │
   ┌────────────┐  ┌─────────┐  │    │
   │ vuln_scan  │  │ triage  │  │    │
   │ (ReAct)    │  │(struct) │◄      │
   └─────┬──────┘  └────┬────┘       │
         │              │            │
         ▼              │            │
   ┌──────────┐         │            │
   │  triage  │         │            │
   │ (struct) │         │            │
   └─────┬────┘         │            │
         │              │            │
         ▼              ▼            ▼
   ┌──────────────────────────────────┐
   │           report_node            │
   │         (LLM synthesis)          │
   └──────────────┬───────────────────┘
                  │
                 END

Each phase is a LangGraph node. The orchestrator manages state flow, conditional routing, and accumulates findings across phases.

See docs/architecture.md for full architectural details.


Terminal UI

Fackel streams the whole run to the terminal in real time (see the demo above). The renderer is built on Rich and designed so you can follow autonomous agents at a glance:

ElementWhat you see
Pipeline stepperA persistent breadcrumb — ✓ OSINT ● Port Scan ○ Vuln Scan ○ Triage ○ Report — so you always know where the run is.
Parallel agent lanesWhen specialists fan out (OSINT, Vuln Scan), each runs in its own live lane with its own spinner, tool activity, and reasoning — no interleaved soup.
Per-tool timingEvery tool call settles to ✓ tool_name … 1.2s, with errors surfaced inline and duplicate errors collapsed.
Live context meterA token gauge (ctx 12.3k/120k ▓▓▓░░) tracks how full the agent context window is as the scan runs.
Inline approval gatesThe human-in-the-loop gate pauses the live area and prompts before any active scanning — same panel whether you use the harness or fackel scan.
Brand wordmarkA flame-gradient block banner on startup, with an automatic compact fallback on narrow terminals.

Pass -v / --verbose to expand each phase's LLM reasoning and full tool-result previews. Glyphs use a Nerd Font by default; set FACKEL_NERD_FONT=0 for an alignment-safe ASCII rendering.


Specialist agents

AgentTypeToolsPurpose
OSINTReAct27 toolsPassive reconnaissance — DNS, WHOIS, subdomains (subfinder, crt.sh, VirusTotal, Amass), reverse DNS, Shodan/Censys/FOFA, IP enrichment, TLS certs, historical DNS, passive URL discovery (gau), cloud resource enumeration (CloudBrute), web tech fingerprinting (WhatWeb), parameter discovery (ParamSpider), JS endpoint extraction (LinkFinder), subdomain takeover (Subzy), secret scanning (TruffleHog), job search, email analysis
Port ScanReAct2 toolsActive scanning — discover open ports (naabu) and fingerprint services (nmap)
Vuln ScanReAct12 toolsVulnerability scanning — Nuclei templates, XSS detection (DalFox), HTTP tech detection, WAF detection, web crawling, S3 bucket audit, TLS analysis, WordPress scanning (WPScan), CORS misconfiguration (Corsy)
TriageStructured LLM(none)Gap analysis — identify technologies found but not assessed, flag coverage gaps
ReportLLM chain(none)Synthesize all findings, evaluations, and gaps into a Markdown pentest report
JudgeStructured LLM(none)Quality evaluator — scores each phase (0.0–1.0) and recommends routing

See docs/agents.md for detailed agent documentation.


Tool inventory

ToolTarget TypeRequiresAgent
dns_resolveHOST—OSINT
whois_lookupDOMAINwhois binaryOSINT
shodan_lookup(custom)SHODAN_API_KEYOSINT
censys_lookupHOSTCENSYS_API_ID + CENSYS_API_SECRETOSINT
dnsdumpster_lookupDOMAIN—OSINT
virustotal_subdomain_enumDOMAINVIRUSTOTAL_API_KEYOSINT
crtsh_subdomain_enumDOMAIN—OSINT
subfinder_enumDOMAINsubfinder binaryOSINT
reverse_dns_lookupIP—OSINT
ipinfo_lookupIP—OSINT
bgp_lookupIP—OSINT
httpx_scanHOST_OR_URLhttpx binaryOSINT, Vuln Scan
tlscert_lookupDOMAIN—OSINT
securitytrails_historyDOMAINSECURITYTRAILS_API_KEYOSINT
urlscan_searchDOMAIN—OSINT
otx_passive_dnsDOMAINOTX_API_KEYOSINT
fofa_search(custom)FOFA_EMAIL + FOFA_KEYOSINT
gau_urlsDOMAINgau binaryOSINT
cloudbrute_enum(keyword)cloudbrute binaryOSINT
job_search(free text)—OSINT
analyze_email(email)HIBP_API_KEY / EMAILREP_API_KEYOSINT
naabu_scanHOSTnaabu binaryPort Scan
nmap_port_scanHOSTnmap binaryPort Scan
nuclei_scanDOMAINnuclei binaryVuln Scan
wafw00f_detectHOST_OR_URLwafw00f binaryVuln Scan
graphql_scanURL—Vuln Scan
feroxbuster_scanHOST_OR_URLferoxbuster binaryVuln Scan
katana_crawlHOST_OR_URLkatana binaryVuln Scan
testssl_scanHOSTtestssl.sh binaryVuln Scan
dalfox_scanHOST_OR_URLdalfox binaryVuln Scan
s3scanner_scan(bucket name)s3scanner binaryVuln Scan
extract_webpage_contentURL—Vuln Scan
amass_enumDOMAINamass binaryOSINT
subzy_checkDOMAINsubzy binaryOSINT
paramspider_crawlDOMAINparamspider binaryOSINT
whatweb_scanHOST_OR_URLwhatweb binaryOSINT
linkfinder_extractHOST_OR_URLlinkfinder binaryOSINT
trufflehog_scan(repo URL)trufflehog binaryOSINT
wpscan_scanHOST_OR_URLwpscan binary + WPSCAN_API_TOKENVuln Scan
corsy_scanHOST_OR_URLcorsy binaryVuln Scan

See docs/tools.md for complete tool reference with input schemas and validation rules.


Configuration

Model per agent

Each agent reads its model from an environment variable, falling back to gpt-5-mini:

VariableAgentDefault
FACKEL_MODEL_OSINTOSINT agentgpt-5-mini
FACKEL_MODEL_PORT_SCANPort scan agentgpt-5-mini
FACKEL_MODEL_VULN_SCANVuln scan agentgpt-5-mini
FACKEL_MODEL_TRIAGETriage agentgpt-5-mini
FACKEL_MODEL_REPORTReport generatorgpt-5-mini
FACKEL_MODEL_JUDGEPhase quality evaluatorgpt-5-mini
# Use a more capable model for report generation
export FACKEL_MODEL_REPORT=gpt-4o

LLM provider

Fackel uses LangChain's init_chat_model and supports OpenAI (default) and Ollama (local-first).

OpenAI

The default LLM provider. Requires OPENAI_API_KEY:

export OPENAI_API_KEY=sk-...
export FACKEL_DEFAULT_MODEL=gpt-5-mini
# or per-agent:
export FACKEL_MODEL_REPORT=gpt-4o

The default model is gpt-5-mini, which your OpenAI account must have access to. If a scan fails immediately with a model/authorization error, set FACKEL_DEFAULT_MODEL to a model you can use (e.g. gpt-4o-mini).

Ollama

Run LLMs locally with Ollama. Install Ollama, then pull a tool-calling-capable model:

ollama pull llama3.1
# or: ollama pull qwen2.5

Set environment variables:

export FACKEL_LLM_PROVIDER=ollama
export FACKEL_DEFAULT_MODEL=llama3.1
# Optional — default is http://localhost:11434
export FACKEL_OLLAMA_BASE_URL=http://ollama.internal:11434

Or use the provider:model prefix syntax to override per-agent:

export FACKEL_MODEL_REPORT=ollama:llama3.1
export FACKEL_MODEL_OSINT=openai:gpt-4o-mini

Model requirements: ReAct agents need tool-calling support. Recommended Ollama models: llama3.1, llama3.2, qwen2.5, qwen2.5-coder, mistral-nemo, mistral (≥ v0.3), command-r. Models without tool support work for simple text generation but will fail in scanning agents.

Per-agent override

Mix providers and models across agents:

export FACKEL_MODEL_OSINT=openai:gpt-4o-mini      # Fast OpenAI model
export FACKEL_MODEL_REPORT=ollama:qwen2.5         # Local Ollama
export FACKEL_MODEL_VULN_SCAN=openai:gpt-4o       # Capable OpenAI model

API keys

VariableRequiredUsed by
OPENAI_API_KEYYesAll agents (LLM)
SHODAN_API_KEYNoshodan_lookup
VIRUSTOTAL_API_KEYNovirustotal_subdomain_enum
CENSYS_API_ID / CENSYS_API_SECRETNocensys_lookup
FOFA_EMAIL / FOFA_KEYNofofa_search
SECURITYTRAILS_API_KEYNosecuritytrails_history
OTX_API_KEYNootx_passive_dns
HIBP_API_KEYNoanalyze_email (graceful degradation)
EMAILREP_API_KEYNoanalyze_email (graceful degradation)
WPSCAN_API_TOKENNowpscan_scan

Tools with missing API keys (and hard_fail=True) are automatically removed from agents, preventing the LLM from attempting calls that would fail.

Persistence

Scans persist to a file-based JSONL store — no database or extra service to run. Each scan writes an append-only set of JSONL files (executions.jsonl, records.jsonl, timeline.jsonl, edges.jsonl) under FACKEL_DATA_DIR (default ~/.fackel/data), which the fackel scans, fackel diff, fackel graph, and fackel ask commands read back.

Observability (optional)

Fackel uses LangSmith for LLM observability. Set the env vars and all agent traces appear automatically:

export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY=lsv2_pt_...
export LANGSMITH_PROJECT=fackel

See docs/configuration.md for full configuration reference.


Python API

from fackel.agents.orchestrator import run

# Blocking — returns final state
result = run("example.com", active_scan=True)
print(result["report"])

Adding new tools

Add a @fackel_tool function under src/fackel/tools/ (Pydantic input schema, guard_target() on every target) and wire it into the owning agent. The LLM decides when to use it from its docstring and the agent's system prompt. The step-by-step checklist is in docs/development.md.

See docs/development.md for the full development guide.


Documentation

DocumentDescription
docs/architecture.mdSystem architecture, graph flow, state management, prompt system
docs/agents.mdAgent specifications, prompts, LLM-as-a-judge evaluator
docs/tools.mdComplete tool reference — schemas, validation, binaries
docs/input-validation.mdInput validation system — TargetType, guard_target, security
docs/configuration.mdEnvironment variables, API keys, model selection, infrastructure
docs/development.mdContributing guide, adding tools, coding standards, testing

Development

# Install dev dependencies
uv sync --python 3.12 --extra dev

# Lint
uv run ruff check src/

# Type check
uv run mypy src/

# Tests
uv run pytest tests/

# Format
uv run ruff format src/

License

Apache 2.0 — see LICENSE.

Collected info

  • ★ 9 stars
  • ⎇ 1 forks
  • Language: Python
  • Source updated: 9/19/2026