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

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 (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 (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. 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:


# 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.

Building a Logging and Analytics Hook

Capture detailed compression metrics for monitoring or cost analysis:


# 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.

Handling Pipeline Events with on_pipeline_event

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


# 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.

Integrating Hooks into ProxyConfig

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


# 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 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.
  • 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, 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. 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →