# `ExAthena.Compactor.Pipeline`
[🔗](https://github.com/udin-io/ex_athena/blob/v0.7.1/lib/ex_athena/compactor/pipeline.ex#L1)

Multi-stage context-compaction runner.

The Claude Code paper describes Anthropic's compaction as a five-layer
pipeline (Budget Reduction → Snip → Microcompact → Context Collapse →
Auto-Compact / Summary), each layer cheaper than the next. The
cheaper layers run first; the LLM-summary layer fires only when
deterministic shrinkage couldn't get the conversation under target.

The pipeline implements the existing `ExAthena.Compactor` behaviour,
so `loop.ex` doesn't have to change — the kernel still calls
`compactor.should_compact?/2` then `compactor.compact/2`. Internally
this module dispatches across a list of `ExAthena.Compactor.Stage`
modules.

## Configuration

The stage list is read from `state.meta[:compaction_pipeline]`,
falling back to `ExAthena.Compactor.Stage.default_pipeline/0`. Hosts
can swap individual stages or replace the list entirely.

    Loop.run("hi",
      provider: ...,
      compactor: ExAthena.Compactor.Pipeline,
      compaction_pipeline: [MyApp.MyStage, ExAthena.Compactors.Summary]
    )

## Reactive recovery

When a mode signals `:error_prompt_too_long`, the kernel re-invokes
the pipeline with `force: true`, which runs every stage regardless
of cost. See `run/3`.

# `run`

```elixir
@spec run(ExAthena.Loop.State.t(), ExAthena.Compactor.estimate(), keyword()) ::
  ExAthena.Compactor.decision()
```

Run the pipeline. `force: true` makes every stage attempt
compaction unconditionally; this is the reactive-recovery path the
loop uses after a context-window error from the provider.

Returns `{:compact, messages, metadata}` if at least one stage
reduced the conversation, `:skip` if every stage declined, or
`{:error, reason}` on the first stage that surfaces an error.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
