# What Is the TrioProgress Instrument in Holehe and How Does It Show Progress?

> Learn about TrioProgress, the holehe instrumentation hook that displays asynchronous task progress with a visual tqdm bar. Understand how it works and its benefits.

- Repository: [Palenath/holehe](https://github.com/megadose/holehe)
- Tags: deep-dive
- Published: 2026-08-15

---

**The TrioProgress instrument is a lightweight trio instrumentation hook in holehe that bridges asynchronous task completion events to a visual tqdm progress bar.**

Holehe is an OSINT tool that checks email addresses against hundreds of websites simultaneously. Because these checks run concurrently via **trio**, the project needs a non-blocking way to display progress to users. The `TrioProgress` class provides this by tapping into trio's low-level instrumentation API.

## How TrioProgress Fits Into Holehe's Architecture

The instrument sits between trio's task scheduler and the user's terminal. Rather than modifying every site-checking module to report status, holehe registers a single global observer that watches for task lifecycle events.

In [[`holehe/instruments.py`](https://github.com/megadose/holehe/blob/main/holehe/instruments.py)](https://github.com/megadose/holehe/blob/master/holehe/instruments.py), the class is defined as:

```python
from tqdm import tqdm

class TrioProgress:
    def __init__(self, total):
        self.tqdm = tqdm(total=total)

    def task_exited(self, task):
        if task.name.split(".")[-1] == "launch_module":
            self.tqdm.update(1)

```

The `task_exited` method is trio's standard instrumentation callback. TrioProgress filters these events by task name, looking specifically for `"launch_module"`—the coroutine that wraps each site's check.

## Where TrioProgress Is Created and Registered

The instrument lifecycle is managed in [[`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py)](https://github.com/megadose/holehe/blob/master/holehe/core.py). Here's the exact integration:

```python

# From holehe/core.py, lines 16-17

instrument = TrioProgress(len(websites))
trio.lowlevel.add_instrument(instrument)

```

This happens before any site checks begin. The `len(websites)` parameter tells tqdm how many total increments to expect.

## How the Progress Bar Updates in Real Time

When trio schedules a `launch_module` task, it eventually exits—either successfully or with an exception. At that moment:

1. Trio calls `instrument.task_exited(task)` for every finished task
2. The instrument checks if `task.name.split(".")[-1] == "launch_module"`
3. If matched, `self.tqdm.update(1)` advances the bar by one unit

After all modules complete, holehe cleans up:

```python
trio.lowlevel.remove_instrument(instrument)

```

This prevents memory leaks and ensures the progress bar finalizes properly.

## Complete Working Example

This standalone script demonstrates the same pattern holehe uses internally:

```python
import trio
from tqdm import tqdm

class TrioProgress:
    def __init__(self, total):
        self.tqdm = tqdm(total=total, desc="Checking sites")

    def task_exited(self, task):
        if task.name.split(".")[-1] == "launch_module":
            self.tqdm.update(1)

    def close(self):
        self.tqdm.close()

async def launch_module(site_id):
    """Simulates a site check taking variable time."""
    await trio.sleep(0.1 + site_id * 0.05)

async def main():
    sites = ["twitter", "github", "gitlab", "instagram", "reddit"]
    
    # Create and register the instrument

    prog = TrioProgress(len(sites))
    trio.lowlevel.add_instrument(prog)
    
    try:
        async with trio.open_nursery() as nursery:
            for site in sites:
                nursery.start_soon(launch_module, site)
    finally:
        # Always clean up the instrument

        trio.lowlevel.remove_instrument(prog)
        prog.close()

if __name__ == "__main__":
    trio.run(main)

```

Running this displays a live tqdm bar that increments as each `launch_module` task exits, identical to holehe's behavior during email verification.

## Key Design Decisions in TrioProgress

- **Task name filtering**: Uses string splitting on `task.name` rather than identity checks, keeping the instrument decoupled from specific coroutine objects
- **Minimal API surface**: Only implements `task_exited`, ignoring other trio hooks like `task_scheduled` or `before_io_wait`
- **External tqdm instance**: Delegates all rendering to tqdm rather than custom terminal code, ensuring compatibility across platforms

## Summary

- **TrioProgress** is a trio `Instrument` subclass that converts task exit events into progress bar updates
- Located in [`holehe/instruments.py`](https://github.com/megadose/holehe/blob/main/holehe/instruments.py), it wraps a `tqdm` bar and increments when `launch_module` tasks finish
- Registered in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) before site checks begin and removed after completion
- Enables real-time feedback without modifying individual checking modules or blocking the event loop

## Frequently Asked Questions

### What is a trio instrument?

A trio instrument is a class that implements specific callback methods to observe low-level task scheduling events. Trio calls these methods at key moments—task creation, execution, I/O operations, and exit—allowing external code to monitor or modify behavior without changing task code.

### Why does TrioProgress check task.name instead of using a counter?

The task name check ensures the progress bar only increments for actual site checks, not for internal trio tasks or nursery management. In holehe, `launch_module` is the specific coroutine that performs each site's verification, so filtering by name provides accurate progress tracking.

### Can TrioProgress work with other async libraries?

No—trio instruments are specific to trio's scheduling system. The `trio.lowlevel.add_instrument` API is proprietary to trio. For asyncio, you would need a different approach such as `asyncio.Queue`-based progress reporting or manual callback injection.

### Does using TrioProgress slow down holehe's performance?

The overhead is negligible. The `task_exited` callback performs only a string split, equality check, and integer increment—operations measured in microseconds. The tqdm update batches terminal writes efficiently, so the instrument adds no perceptible latency to concurrent site checks.