# How the Core Execution Flow Starts in Holehe: From CLI to Async Sign-up Detection

> Explore Holehe's core execution flow. Discover how CLI commands trigger async Trio runners and concurrent HTTP requests across hundreds of modules for efficient sign-up detection.

- Repository: [Palenath/holehe](https://github.com/megadose/holehe)
- Tags: internals
- Published: 2026-08-24

---

**The core execution flow in Holehe starts at the `holehe.core:main` entry point, which delegates to a Trio-powered async runner in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) that orchestrates concurrent HTTP requests across hundreds of site-checking modules.**

Holehe is an open-source command-line tool developed by megadose that discovers whether an email address is registered on online services. Tracing the core execution flow reveals how the program transforms a single terminal command into a high-concurrency reconnaissance scan across hundreds of platforms.

## Entry Point and the Main Function

The journey begins in the package configuration file ([`setup.py`](https://github.com/megadose/holehe/blob/main/setup.py) or [`pyproject.toml`](https://github.com/megadose/holehe/blob/main/pyproject.toml)), which declares the console script entry point:

```python
entry_points={
    'console_scripts': [
        'holehe = holehe.core:main',
    ],
}

```

When a user runs the `holehe` command, Python invokes the `main()` function located in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py). This function immediately hands control to the Trio event loop:

```python
def main():
    trio.run(maincore)

```

The `main()` function serves as a thin wrapper that starts the asynchronous runtime. It contains minimal logic, ensuring that all heavy lifting occurs within the async context managed by `maincore()`.

## Argument Parsing and Module Discovery in maincore()

Once inside `maincore()`, the execution flow handles initialization and discovery:

```python
def maincore():
    parser = ArgumentParser(description='holehe checks if email is used on different sites')
    args = parser.parse_args()
    credit()
    email = args.email[0]

```

This phase performs several critical setup operations:

- **Email validation** via `is_email()` to ensure the target address is properly formatted
- **Update checking** via `check_update()` to notify users of new releases
- **Dynamic module importing** via `import_submodules()` and `get_functions()` to discover every site-checker under `holehe/modules`

The `get_functions()` call returns a list of callable site-check functions extracted from submodules like `holehe.modules.amazon` or `holehe.modules.twitter`. This dynamic discovery allows Holehe to automatically include new checkers as they are added to the modules directory without modifying the core logic.

## Asynchronous Orchestration with Trio and HTTPX

With modules loaded, the execution flow enters the concurrent phase. The code initializes an HTTPX async client and sets up a Trio nursery to manage parallel tasks:

```python
client = httpx.AsyncClient(timeout=timeout)
out = []
instrument = TrioProgress(len(websites))
trio.lowlevel.add_instrument(instrument)

async with trio.open_nursery() as nursery:
    for website in websites:
        nursery.start_soon(launch_module, website, email, client, out)

trio.lowlevel.remove_instrument(instrument)

```

Key components of this phase include:

- **`httpx.AsyncClient`** – Creates a reusable HTTP connection pool with configurable timeouts for all site requests
- **`trio.open_nursery()`** – Opens a structured concurrency context where each site-check runs as a separate task
- **`nursery.start_soon()`** – Schedules the `launch_module()` coroutine for each discovered website without blocking
- **`TrioProgress`** – An instrument (defined in [`holehe/instruments.py`](https://github.com/megadose/holehe/blob/main/holehe/instruments.py)) that renders a progress bar as modules complete

The `launch_module()` coroutine (defined in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) lines 66-78) wraps each site-specific checker. It catches exceptions internally, ensuring that a failure in one module (e.g., a timeout on Amazon) does not crash the entire scan:

```python
async def launch_module(module, email, client, out):
    try:
        await module(email, client, out)
    except Exception:
        out.append({"name": module.__name__, "exists": False, "emailrecovery": None, "others": None})

```

## Result Aggregation and Finalization

After all nursery tasks complete, the execution flow shifts to data presentation and export:

```python
out = sorted(out, key=lambda i: i['name'])
await client.aclose()
print_result(out, args, email, start_time, websites)
credit()
export_csv(out, args, email)

```

The results are sorted alphabetically by service name, the HTTP client is gracefully closed, and output is rendered through `print_result()`. Depending on command-line flags, the tool may also invoke `export_csv()` to write findings to disk.

## Summary

- **Entry point**: The `holehe` command maps to `holehe.core:main` via package configuration
- **Async bootstrap**: `main()` immediately invokes `trio.run(maincore)` to enter the asynchronous runtime
- **Module discovery**: `maincore()` dynamically imports all site-checkers from `holehe/modules` using `get_functions()`
- **Concurrent execution**: A Trio nursery spawns hundreds of `launch_module()` tasks sharing a single `httpx.AsyncClient`
- **Graceful degradation**: Individual module failures are caught and logged without terminating the scan
- **Output**: Results are sorted, displayed with color-coding, and optionally exported to CSV

## Frequently Asked Questions

### What is the role of Trio in Holehe's core execution flow?

Trio provides the structured concurrency framework that manages the execution flow. In [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py), the `main()` function starts the Trio event loop with `trio.run(maincore)`, and the `open_nursery()` context manager ensures that hundreds of site-checking tasks run concurrently without resource leaks or zombie processes.

### How does Holehe handle errors in individual site checkers?

The `launch_module()` coroutine in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) wraps each site-specific function in a try-except block. If a module raises an exception (network timeout, parsing error, etc.), the code catches it and appends a default error result to the output list, allowing the remaining checks to continue uninterrupted.

### What is the purpose of the instruments.py file in the execution flow?

[`holehe/instruments.py`](https://github.com/megadose/holehe/blob/main/holehe/instruments.py) implements the `TrioProgress` class, which is registered as a Trio instrument using `trio.lowlevel.add_instrument()`. This hooks into Trio's task scheduling system to display a real-time progress bar showing how many site checks have completed versus the total number of modules loaded.

### Can I modify the timeout for HTTP requests in Holehe?

Yes. The timeout value is passed to `httpx.AsyncClient(timeout=timeout)` during the initialization phase in `maincore()`. Users can adjust this parameter by modifying the client initialization code or by passing command-line arguments that control the timeout duration before the async client is instantiated.