# How to Configure Compression Pipeline Hooks in Headroom: A Complete Guide

> Learn to configure compression pipeline hooks in Headroom. This guide details subclassing CompressionHooks, implementing lifecycle methods, and passing an instance for custom compression.

- Repository: [Tejas Chopra/headroom](https://github.com/chopratejas/headroom)
- Tags: how-to-guide
- Published: 2026-06-14

---

**To configure compression pipeline hooks in Headroom, subclass `CompressionHooks` from `headroom.hooks`, implement the lifecycle methods (`pre_compress`, `compute_biases`, `post_compress`), and pass an instance to `ProxyConfig.hooks` when initializing the proxy.**

Headroom is an open-source LLM proxy that compresses request contexts to reduce token costs. Configuring compression pipeline hooks in Headroom allows you to intercept, modify, and monitor the compression process at well-defined stages of the request lifecycle without modifying core pipeline code.

## Understanding the Compression Hooks Architecture

Headroom’s hook system centers on a single abstract base class that defines extension points for the compression pipeline. The architecture separates concerns between the proxy configuration layer, the hook implementations, and the transform pipeline itself.

### The CompressionHooks Base Class

The **`CompressionHooks`** class in [`headroom/hooks.py`](https://github.com/chopratejas/headroom/blob/main/headroom/hooks.py) (lines 21–51) defines four extension methods with default no-op implementations:

- `pre_compress(messages, ctx)` – Called before any transforms run
- `compute_biases(messages, ctx)` – Called after pre-processing but before compression
- `post_compress(event)` – Called after the pipeline completes
- `on_pipeline_event(event)` – Optional handler for pipeline lifecycle events

All methods have default implementations, so you only override the stages you need.

### CompressContext and CompressEvent Data Classes

Hooks receive context through two specialized dataclasses defined in the same file:

- **`CompressContext`** carries conversation metadata including model name, user query, turn number, tool calls, and provider information.
- **`CompressEvent`** contains post-compression metrics including `tokens_before`, `tokens_after`, `tokens_saved`, compression ratios, and applied transform names.

### ProxyConfig Integration

The **`ProxyConfig`** dataclass in [`headroom/proxy/models.py`](https://github.com/chopratejas/headroom/blob/main/headroom/proxy/models.py) (lines 79–81) accepts a `hooks` parameter that holds your custom implementation. When the proxy server processes requests, it extracts this hook object and invokes the appropriate methods at each pipeline stage.

## Hook Execution Lifecycle

The proxy orchestrates hook calls around the `TransformPipeline.apply` method in [`headroom/transforms/pipeline.py`](https://github.com/chopratejas/headroom/blob/main/headroom/transforms/pipeline.py). Execution follows this strict sequence:

1. **`pre_compress`** receives the full message list and `CompressContext`. Use this to rewrite, filter, or inject messages before compression begins.

2. **`compute_biases`** returns a dictionary mapping message indices to bias factors. Values greater than 1.0 indicate "keep more tokens"; values less than 1.0 indicate "compress harder."

3. **`post_compress`** receives a `CompressEvent` containing token counts and compression statistics. Use this for logging, analytics, or feedback loops.

4. **`on_pipeline_event`** receives any `PipelineEvent` emitted during execution. Return a modified event to augment or replace the default event handling.

## Implementing Custom Hooks

### Creating a Position-Aware Bias Hook

The following implementation biases the compression algorithm to preserve the middle of a conversation, where context is often most relevant:

```python

# my_hooks.py

from headroom.hooks import CompressionHooks, CompressContext

class PositionBiasHooks(CompressionHooks):
    def compute_biases(self, messages, ctx: CompressContext):
        """Apply higher bias to center messages to preserve them."""
        biases = {}
        n = len(messages)
        for i in range(n):
            pos = i / max(n - 1, 1)  # Normalize to 0.0–1.0

            # Peak bias at center (pos ≈ 0.5)

            biases[i] = 1.0 + 0.5 * (1.0 - abs(2 * pos - 1))
        return biases

```

This override matches the signature documented at lines 21–27 of [`headroom/hooks.py`](https://github.com/chopratejas/headroom/blob/main/headroom/hooks.py).

### Building a Logging and Analytics Hook

Capture detailed compression metrics for monitoring or cost analysis:

```python

# logging_hooks.py

import logging
from headroom.hooks import CompressionHooks, CompressEvent

log = logging.getLogger("headroom.hooks")

class MetricsHooks(CompressionHooks):
    def post_compress(self, event: CompressEvent) -> None:
        """Log compression savings and ratios."""
        if event.tokens_before > 0:
            savings_pct = (event.tokens_saved / event.tokens_before) * 100
        else:
            savings_pct = 0
            
        log.info(
            "Compression: %d → %d tokens (saved %d, %.1f%%)",
            event.tokens_before,
            event.tokens_after,
            event.tokens_saved,
            savings_pct
        )

```

The `post_compress` method signature and `CompressEvent` attributes are defined at lines 31–44 of [`headroom/hooks.py`](https://github.com/chopratejas/headroom/blob/main/headroom/hooks.py).

### Handling Pipeline Events with on_pipeline_event

For advanced lifecycle management, intercept pipeline events to inject custom attributes:

```python

# lifecycle_hooks.py

from headroom.hooks import CompressionHooks, PipelineEvent

class LifecycleHooks(CompressionHooks):
    def on_pipeline_event(self, event: PipelineEvent) -> PipelineEvent | None:
        """Augment events with custom metadata."""
        event.attributes["custom_tracking_id"] = "my-app-v1"
        return event

```

This optional hook is documented at lines 45–51 of [`headroom/hooks.py`](https://github.com/chopratejas/headroom/blob/main/headroom/hooks.py).

## Integrating Hooks into ProxyConfig

After implementing your subclass, wire it into the proxy configuration:

```python

# server_startup.py

from headroom.proxy.server import HeadroomProxy, ProxyConfig
from my_hooks import PositionBiasHooks

config = ProxyConfig(hooks=PositionBiasHooks())
proxy = HeadroomProxy(config)

```

The proxy server reads `config.hooks` during request handling and invokes `pre_compress`, `compute_biases`, and `post_compress` at the appropriate stages. If `on_pipeline_event` is implemented, the pipeline dispatches events to your handler before final processing.

## Summary

- **Subclass `CompressionHooks`** from [`headroom/hooks.py`](https://github.com/chopratejas/headroom/blob/main/headroom/hooks.py) to customize compression behavior.
- **Implement lifecycle methods**: `pre_compress` for pre-processing, `compute_biases` for token allocation control, and `post_compress` for analytics.
- **Pass hook instances** to `ProxyConfig(hooks=...)` as defined in [`headroom/proxy/models.py`](https://github.com/chopratejas/headroom/blob/main/headroom/proxy/models.py).
- **Access rich context** through `CompressContext` (input metadata) and `CompressEvent` (output metrics).
- **Maintain backward compatibility** by only overriding the methods you need; default no-op implementations preserve existing behavior.

## Frequently Asked Questions

### What is the difference between pre_compress and compute_biases?

**`pre_compress`** runs before any transforms and allows you to modify the message list itself—filtering, reordering, or injecting content. **`compute_biases`** runs after pre-processing but before the actual compression transforms, and it only returns a mapping of indices to bias factors that influence how aggressively each message is compressed. Use `pre_compress` for structural changes; use `compute_biases` for soft weighting without modifying content.

### Can I use multiple hooks simultaneously?

Headroom’s `ProxyConfig` accepts a single `hooks` instance. To combine multiple behaviors, create a composite hook class that inherits from `CompressionHooks` and delegates to your individual implementations, or chain logic within a single class by calling multiple internal methods from each lifecycle hook.

### How do I access turn number and model metadata in hooks?

The **`CompressContext`** object passed to `pre_compress` and `compute_biases` contains attributes for `turn_number`, `model_name`, `provider`, and `tool_calls`. According to the source in [`headroom/hooks.py`](https://github.com/chopratejas/headroom/blob/main/headroom/hooks.py), this dataclass carries all conversation metadata from the proxy layer into your hook implementation.

### Are hooks required for Headroom to function?

No. All methods in `CompressionHooks` have default no-op implementations in [`headroom/hooks.py`](https://github.com/chopratejas/headroom/blob/main/headroom/hooks.py). If you do not provide a custom `hooks` instance to `ProxyConfig`, the proxy operates with the default behavior, applying the standard compression pipeline without custom pre-processing, biasing, or post-processing logic.