Skip to content

Getting started

Quick start

pip install borges                   # or: uv pip install borges
borges init                          # writes config.yaml (prompts, blocklists), .env and data/
borges download                      # latest PeeringDB + AS2Org snapshots into data/input/
borges pipeline run                  # needs an LLM key, or see below to skip it

From a clone (for development):

git clone https://github.com/NU-AquaLab/borges.git
cd borges
uv venv && source .venv/bin/activate
uv pip install -e ".[dev]"

Usage

Pipeline stages

# Stage What it does LLM
1 load_data Load PeeringDB and WHOIS (AS2Org) data
2 redirect_scraping Follow each PeeringDB website to its final URL (no HTML stored)
3 as_detection Extract sibling ASNs from notes and aka 🤖
4 redirect_analysis Group networks that share a final URL
5 favicon_download Download website favicons
6 favicon_analysis Decide whether shared favicons mean a shared company 🤖
7 whois_processing Group ASes by AS2Org organization
8 network_consolidation Merge groups from all sources
9 export_results Write Parquet/JSON/CSV and reports to data/output/

Commands

borges pipeline list                                   # stages and their dependencies
borges pipeline run                                    # full run
borges pipeline run --stage redirect_scraping --stage as_detection   # selected stages
borges pipeline run --skip favicon_analysis            # skip stages
borges pipeline run --resume                           # continue from checkpoints
borges pipeline run --dry-run                          # show what would run
borges --config my-config.yaml pipeline run            # or: export BORGES_CONFIG=...
borges download --peeringdb-date 2025-07-16 --as2org-date 2025-07-01

borges --help lists the rest (report generate, favicon download, config, version).

Running without a paid API key

Only stages 3 and 6 call an LLM. Pick one option:

Option How Trade-off
Skip the LLM stages borges pipeline run --skip as_detection --skip favicon_analysis No sibling extraction from notes/aka, no favicon grouping
Free local model Any OpenAI-compatible server: vLLM on a GPU, Ollama, LM Studio. Set base_url (below) Results differ from the paper, which used gpt-4o-mini
OpenAI OPENAI_API_KEY=... in .env About US$3 per full run

With Ollama (ollama pull qwen3:8b and ollama pull qwen3-vl:8b-instruct), set this in config.yaml:

api:
  llm:
    base_url: http://localhost:11434/v1
    model: qwen3:8b
    vision_model: qwen3-vl:8b-instruct
    structured_output: true              # force parseable JSON answers
    timeout: 300
    extra_body:
      reasoning_effort: none             # turn off thinking: much faster

For open-weight models on a GPU (Qwen3, GLM, Kimi on vLLM), concurrency and the answer cache, see docs/local-llm.md. A full run with Qwen3 agrees with gpt-4o-mini on 99.4% of sibling extractions; the evaluation has the details and limitations.

Programmatic use

from borges.config import load_config, set_config
from borges.pipeline import Pipeline

config = load_config("config.yaml")
set_config(config)
pipeline = Pipeline(config)
results = pipeline.run(skip_stages=["as_detection", "favicon_analysis"])

Output

export_results writes timestamped files to data/output/:

File Contents
autonomous_systems_*.parquet One row per AS
organizations_*.parquet Organization groupings
relationships_*.parquet Detected sibling relationships and their source
network_groups_*.parquet Consolidated groups of sibling ASes
redirect_analysis_*.parquet Final URL of each network's website
network_report_*.json Full analysis report
export_summary_*.json Export metadata and statistics

The main settings in config.yaml:

Key Default Purpose
api.llm.model / vision_model gpt-4o-mini Text and vision models
api.llm.base_url (unset: OpenAI) Any OpenAI-compatible endpoint
api.llm.request_delay / retry_delay 0 / 30 s Rate limiting
scraping.html.max_workers / timeout 100 / 30 s Redirect scraping parallelism
scraping.favicon.max_workers 50 Favicon download parallelism
peeringdb_asn_exclusions, blocklists see file Known false organizational bridges
processing.merge_guard.enabled false Guard against false merges (brand check, bridge guard); see evaluation