SWE-bench Verified, live, four arms: 13% cheaper than no compaction, and the highest reward. See the numbers

The DSL filter engine

DSL engine — powers cmdfilter (lossy)

A declarative, user-extensible text-filter engine authored in YAML (no recompile), wrapped by the cmdfilter Offload component.

How it works

components/dsl is a declarative, user-extensible text-filter engine (adapted from rtk — see THIRD-PARTY-NOTICES), wrapped by cmdfilter. Filters are authored in YAML (no recompile), matched by descending priority then by name, and each runs a fixed 8-stage pipeline. Because filters drop lines they are lossy, which is why the wrapping cmdfilter component is an Offload (it stashes the original first).

flowchart LR
  I[input] --> S1[1 strip_ansi] --> S2["2 replace[]"] --> S3["3 match_output[] + unless"]
  S3 --> S4[4 strip / keep lines] --> S5[5 truncate_lines_at] --> S6[6 head / tail]
  S6 --> S7[7 max_lines] --> S8[8 on_empty] --> O[output + Lossiness]

Filter fields

All optional except match:

priority, and why order matters more here

cmdfilter matches on the shape of the output (a command line is available too, but every shipped filter is shape-keyed) and against several leading lines rather than one — so a generic pattern can shadow a specific one in a way rtk's command matching never had to deal with. This is not hypothetical: widening the selector made gcc start claiming make, swift-build and dotnet-build output, because a bare file:line: error: line appears inside all of them. priority makes specific-before-generic explicit instead of dependent on alphabetical luck. Absent, ordering is by name — exactly the previous behavior.

Rule of thumb: a filter whose selector is a tool banner can be high priority; one whose selector is a generic diagnostic shape must be low, so it only catches what nothing else claimed.

Line budgets: cap classes

Instead of every filter hand-picking a max_lines, a filter selects a budget by signal density. The class names and the first four values are rtk's (src/core/truncate.rs); buildlog is ours.

cap lines for
errors 20 error lists — most actionable, shown the most
warnings 10 warnings — lower signal density than errors
list 20 flat lists (packages, services): one line per item
inventory 50 exhaustive lookups (installed packages, file listings)
buildlog 80 full build/plan transcripts — verbose, and the signal can sit anywhere

cap_reduce: N lowers the chosen cap for an extra-verbose variant, underflow-safe (a deviation can never empty the budget — rtk's reduced helper). Unknown cap names, and a cap_reduce without a cap, are rejected at load. rtk's own TOML filters don't use its cap classes; applying them to the definitions makes the whole set tunable from one map.

Lossiness

Lossiness is reported back to cmdfilter, which uses it to pick the recovery hint:

An intra-line cut from truncate_lines_at types as Whole, since every long line loses its own tail and the loss is non-contiguous by nature. It also appends ..., sized to fit inside the cap so the line never grows — a mid-line cut with no marker reads as corrupted output to a model.

Load-time guardrails

Mirroring rtk's build.rs, a filter document fails at load, not at first use, when:

The shipped filter set must additionally have ≥1 test per filter, and each test's input must route to its own filter (TestEveryBuiltinFilterHasTestsAndRoutes). User-supplied documents aren't required to ship tests, but any they do ship must pass.

Example

schema_version: 1
filters:
  pytest:
    description: keep failures + summary, drop passing noise
    family: tests
    priority: 10
    match: "(pytest|=+ test session starts)"
    strip_lines_matching: ["^\\s*$", " PASSED", "^\\.+$"]
    cap: buildlog
    on_empty: "pytest: all passed"
tests:                       # inline; run at load, and via dsl.RunTests
  pytest:
    - name: all-green
      input: "pytest\n....\n"
      expected: "pytest: all passed"

Documents load with schema_version: 1 and strict unknown-field rejection.

See also: Components overview · cmdfilter · Write a custom DSL filter · Choose a preset