# TTY vs Non-TTY Execution Modes in abx-dl: Output Behavior Explained

> Understand TTY vs non-TTY execution in abx-dl. Learn how it provides interactive dashboards for humans and JSONL streams for automation pipelines.

- Repository: [ArchiveBox/abx-dl](https://github.com/archivebox/abx-dl)
- Tags: deep-dive
- Published: 2026-02-25

---

**`abx-dl` detects terminal interactivity via `sys.stdout.isatty()` and automatically switches between a rich interactive dashboard for humans and machine-readable JSONL streams for automation pipelines.**

The `archivebox/abx-dl` repository implements a dual-mode output system that adapts to its execution environment. When running in an interactive terminal, the tool provides visual feedback through progress bars and summary tables. In non-interactive environments, it streams structured data suitable for piping into other tools.

## How abx-dl Detects TTY Mode

The core detection logic relies on Python’s `sys.stdout.isatty()` method. In **[`abx_dl/executor.py`](https://github.com/archivebox/abx-dl/blob/main/abx_dl/executor.py)**, the `download()` function evaluates this boolean to determine whether stdout is connected to an interactive terminal.

This single check controls multiple downstream behaviors, including UI rendering and output destination selection. The flag propagates through the execution chain, ultimately determining whether results are written silently to files or echoed to standard output.

## TTY Mode: Interactive Dashboard

When `isatty()` returns `True`, `abx-dl` activates its full human-facing interface implemented in **[`abx_dl/cli.py`](https://github.com/archivebox/abx-dl/blob/main/abx_dl/cli.py)** (lines 87-126).

### Visual Progress Indicators

The tool renders **Rich** library components including spinners, progress bars, and formatted summary tables. Users see real-time plugin execution status and dependency warnings styled with colors and formatting.

### Silent File-Only Output

Despite the visual verbosity, TTY mode suppresses JSONL output to stdout. In [`abx_dl/executor.py`](https://github.com/archivebox/abx-dl/blob/main/abx_dl/executor.py) (lines 400-405), the `write_jsonl()` helper receives `also_print=False`, ensuring results are appended only to `index.jsonl` without cluttering the terminal.

### Styled Warning Messages

Dependency warnings and background-hook failures are displayed as formatted console messages when `is_tty` is true. According to the source code in [`abx_dl/executor.py`](https://github.com/archivebox/abx-dl/blob/main/abx_dl/executor.py) (lines 426-432 and 281-287), these messages use Rich styling for immediate visual attention.

## Non-TTY Mode: JSONL Stream for Pipelines

When stdout is not a TTY—such as when piping to `jq` or running in CI environments—the tool switches to machine-readable output.

### Streaming JSON Lines to stdout

In [`abx_dl/executor.py`](https://github.com/archivebox/abx-dl/blob/main/abx_dl/executor.py), the `also_print` parameter is set to `True` when `is_tty` is false. This triggers the printing logic in **[`abx_dl/models.py`](https://github.com/archivebox/abx-dl/blob/main/abx_dl/models.py)** (lines 93-100), where each result record is serialized and written to stdout immediately upon completion.

### No Interactive UI Overhead

The Rich progress components are completely bypassed. Instead of visual feedback, the generator consumes data silently while emitting parseable JSON Lines. This design enables Unix pipeline patterns:

```bash
abx-dl https://example.com | jq '.status'

```

## Key Implementation Details

Three primary files manage the dual-mode behavior:

| File | Function | TTY Behavior | Non-TTY Behavior |
|------|----------|--------------|------------------|
| [`abx_dl/executor.py`](https://github.com/archivebox/abx-dl/blob/main/abx_dl/executor.py) | `download()` | `also_print=False` | `also_print=True` |
| [`abx_dl/cli.py`](https://github.com/archivebox/abx-dl/blob/main/abx_dl/cli.py) | Main command block | Rich UI rendered (lines 87-126) | UI skipped |
| [`abx_dl/models.py`](https://github.com/archivebox/abx-dl/blob/main/abx_dl/models.py) | `write_jsonl()` | File write only | File + stdout print |

The `also_print` flag is the critical switch. When `True`, the function in [`abx_dl/models.py`](https://github.com/archivebox/abx-dl/blob/main/abx_dl/models.py) (lines 93-100) executes `print(json_line, flush=True)` after writing to the index file.

## Practical Examples

### Running in an Interactive Terminal (TTY)

```bash
$ abx-dl https://example.com

```

Output features:
- Animated progress spinner
- Plugin status table
- Final summary screen
- Results stored in `index.jsonl` (not visible on screen)

### Running in a Pipeline (Non-TTY)

```bash
$ abx-dl https://example.com | jq -s '.'

```

Output features:
- Raw JSON Lines streamed to stdout
- No progress indicators or colors
- Each archive result immediately parseable

Example output line:

```json
{"type":"ArchiveResult","plugin":"wget","status":"succeeded","output_files":["wget/wget.html"]}

```

### Capturing Output While Preserving Warnings

Even in non-TTY mode, warnings write to stderr separately from the JSONL stdout stream, allowing proper log separation:

```bash
$ abx-dl https://example.com 2>warnings.log | jq '.'

```

## Summary

- **`abx-dl` uses `sys.stdout.isatty()`** to detect terminal interactivity at runtime in [`abx_dl/executor.py`](https://github.com/archivebox/abx-dl/blob/main/abx_dl/executor.py).
- **TTY mode activates Rich UI components** in [`abx_dl/cli.py`](https://github.com/archivebox/abx-dl/blob/main/abx_dl/cli.py) while suppressing JSONL stdout output via `also_print=False` in [`abx_dl/executor.py`](https://github.com/archivebox/abx-dl/blob/main/abx_dl/executor.py) (lines 400-405).
- **Non-TTY mode streams machine-readable JSON Lines** to stdout through the `write_jsonl()` helper in [`abx_dl/models.py`](https://github.com/archivebox/abx-dl/blob/main/abx_dl/models.py) (lines 93-100), enabling pipeline integration.
- **Warning messages adapt to the mode**: styled in TTY, plain text to stderr in non-TTY.
- **Background hook finalization** respects the same flag (lines 281-287 in [`abx_dl/executor.py`](https://github.com/archivebox/abx-dl/blob/main/abx_dl/executor.py)), ensuring consistent output behavior throughout the execution lifecycle.

## Frequently Asked Questions

### How does abx-dl detect whether it is running in a TTY?

The tool calls `sys.stdout.isatty()` in the `download()` function within [`abx_dl/executor.py`](https://github.com/archivebox/abx-dl/blob/main/abx_dl/executor.py). This standard Python method returns `True` when the output stream is connected to an interactive terminal and `False` when redirected to a pipe or file.

### Why do I see JSON Lines when piping abx-dl but not when running it normally?

In TTY mode, `abx-dl` sets `also_print=False` when calling `write_jsonl()` (lines 400-405 in [`abx_dl/executor.py`](https://github.com/archivebox/abx-dl/blob/main/abx_dl/executor.py)), directing output only to `index.jsonl`. In non-TTY mode, `also_print=True` triggers the print statement in [`abx_dl/models.py`](https://github.com/archivebox/abx-dl/blob/main/abx_dl/models.py) (lines 93-100), emitting each record to stdout for pipeline consumption.

### Can I force JSONL output even when running in a terminal?

While the primary logic hinges on `isatty()`, you can effectively force non-TTY behavior by redirecting stdout through a pipe externally (e.g., `abx-dl URL | cat`). The detection is automatic based on file descriptor properties; there is no separate configuration flag required.

### Does non-TTY mode disable warning messages entirely?

No. Warnings and dependency messages are always written to stderr. In TTY mode, they receive Rich formatting and styling (lines 426-432 in [`abx_dl/executor.py`](https://github.com/archivebox/abx-dl/blob/main/abx_dl/executor.py)). In non-TTY mode, the same messages appear as plain text in the error stream, ensuring visibility without corrupting the JSONL data stream on stdout.