Known external tools

What happens when a user-installed output filter sits between your shell and the agent.

Tools like rtk and Headroom reduce token usage by rewriting command output before the model sees it. Soleur does not adopt, bundle, or endorse them — but users install them independently, and when something then breaks the question becomes "Soleur defect or filter ate the evidence?" This page is the answer key.

The detection marker

At every session boundary (startup|resume|clear|compact) the ext-filter-detect.sh hook emits one systemMessage line per detected tool — or SOLEUR_EXT_FILTER tool=none when nothing is found, so a dead hook is distinguishable from no filter:

SOLEUR_EXT_FILTER tool=<t> version=<v> posture=<p> via=<evidence> measured_at=<date|-> [path=<settings>] ref=soleur.ai/known-external-tools

abbreviated forms:  SOLEUR_EXT_FILTER tool=none ref=soleur.ai/known-external-tools
                    SOLEUR_EXT_FILTER tool=proxy posture=unknown via=proxy-env measured_at=- ref=soleur.ai/known-external-tools

The marker is a stable contract: field names, ordering, and the posture enum are frozen — bug reports and triage muscle memory parse it literally. When several detectors fire, the markers are newline-joined inside one systemMessage object — never N separate objects (the harness's parse must stay single-document). via= is comma-joined evidence: on-path (PATH hit), settings-hook (wired into a settings file), proxy-env (non-default endpoint); a corroborated tool reads via=on-path,settings-hook. systemMessage is operator-facing and costs zero model tokens; severity escalation lives in this page, never in marker adjectives. Any path= field is tilde-collapsed (~/.claude/settings.json) — it never carries your absolute home directory. The marker is Claude-Code-only: Devin, Grok, and other harnesses run no SessionStart hooks, so their sessions have no marker — and that absence does not mean "no filter" (use the manual check in rung 1 below). Kill switch: SOLEUR_DISABLE_EXT_FILTER_DETECT=1.

Posture tiers

posturemeaning
unmeasuredSoleur's gate-literal divergence harness has not run against this tool. Explicitly not an assurance of compatibility.
literal-cleanThe divergence harness measured zero lost gate-literals on the committed corpus. Asserts literal survival only — not behavioral or instruction-following compatibility.
measured-incompatibleGate-literal divergence measured (see Headroom below). Only emitted when the tool's identity is corroborated and its version is at or below the measured version.
tool=proxy posture=unknownANTHROPIC_BASE_URL points at a non-default endpoint. A generic proxy (LiteLLM, Helicone, corporate egress) is never emitted under a vendor name — it is your infrastructure, and its filter posture is simply unknown to us.
tool=noneNo filter detected by any arm. (Not "no filter exists" — four arms can still miss an unusual install.)

Per-tool posture

toolposturebasis
rtk unmeasured Divergence harness has not yet run against rtk on this host (plugins/soleur/scripts/ext-filter-divergence.sh reports SKIPPED reason=rtk-absent here). The posture is a point-in-time statement: when a measurement lands it is stamped measured on rtk <version>, <date>, and after any rtk upgrade re-run the harness — the claim does not follow the tool forward.
Headroom measured-incompatible (≤ v0.37.0) Archived eval, 2026-09-07, headroom-ai==0.37.0, library-mode compress() only: on a corpus of 2,252 tool_result payloads ≥2 kB, 244 of 581 modified payloads dropped at least one gate-relevant literal — including 2,367 file.ext:line citations and 8 SOLEUR_* markers — because the compressor restructures file:line references into a header plus bare line numbers Soleur's greps cannot read. Claim scope: gate-literal integrity under that version and mode.
FCC aux optimizations not applicable free-claude-code's five local optimizations (quota probes, titles, suggestions, filepaths, command prefixes) are proxy-layer intercepts: a plugin cannot observe provider API traffic, so there is no surface for Soleur to judge them on. They are unreachable from plugin hooks, not a finding about their quality.

Methodology is symmetric: the same gate-literal divergence harness is the admission test for every tool — the current asymmetry between rtk and Headroom postures is evidence (one measured, one not yet), not favoritism.

rtk command grammar (canonical table)

Soleur's destructive-command guard unwraps rtk on every invocation shape — a filtered subcommand (rtk git status runs git), an exec subcommand, or the fallback raw exec of an unrecognized word (rtk rm -rf ~ runs rm). The canonical set lives in plugins/soleur/scripts/lib/ext-filter-grammar.tsv (version-pinned; verified 2026-10-13 against src/lib.rs on develop):

exec subcommands:  run|err|test|proxy|bypass|summary
string payloads:   -c | --command | --shell  →  unparsed-wrapper ask, never silent allow
globals:           -v/-vv/-vvv/--verbose, --skip-env, -- (either position — clap global=true; -- is end-of-options)

Coverage caveat: rtk's rewrite hook only intercepts Bash tool calls. Read, Grep, and Glob results are not filtered — savings claims like "90%" are scoped to terminal-output tokens, not your bill.

Boundary-anchor coverage: since #10248, boundary-anchored gates — the gh pr merge review-evidence gate, git commit guards, git stash, gh issue create, prod-write defers — interpolate the shared wrapper-prefix fragment (plugins/soleur/scripts/lib/wrapper-boundary.sh), so rtk gh pr merge, sudo rtk git commit, X=1 rtk gh pr merge and … -- rtk gh pr merge reach them judged. Three residual classes remain BY DESIGN: (1) wrappers and wrapper operands outside the closed atom grammar are not unwrapped — that includes known launchers whose operand words are unmodeled (sudo -u root …, env -C dir …, nice -n N …, timeout N …): the prefix stops at the flag word and the gated command is not reached; (2) opaque string payloads — rtk run -c '…', rtk summary --shell '…' — join the hooks' existing declared-lexical-limit class (alongside bash -c '…', subshells and eval): they are not matchable without parsing a string as shell, which the gates deliberately never do; and (3) sites whose boundary alternation itself differs (e.g. the with_lock … -- member) — prefix tolerance is shared, boundary shape is per-site, tracked at #10315.

Three-rung diagnosis

  1. Check the marker. Scroll to the session-start system messages (or grep the session log) for SOLEUR_EXT_FILTER. Agents can re-derive it: bash <plugin>/hooks/ext-filter-detect.sh --self-test — the flag bypasses the harness-env gates. tool=none means no filter detected — not "no filter exists" (an org-policy settings hook, or a PATH the hook process does not inherit, can still hide one). Claude Code sessions only — a Devin or other-harness session has no marker by design; there, check command -v rtk and ~/.claude/settings.json for hook entries manually.
  2. Reproduce with the filter off. RTK's disable is mode = "disabled" in ~/.config/rtk/config.toml (or remove its hook entry from settings), and the per-command escape is the rtk run/rtk bypass passthrough — there is no RTK_DISABLED env var (it does not exist; verified against RTK's docs 2026-10-13). Headroom's equivalent is removing its plugin/proxy wiring.
  3. Compare verbatim vs filtered. Run the command both ways and diff the evidence the gate needed. plugins/soleur/scripts/ext-filter-divergence.sh automates exactly this over the committed corpus — verdicts LITERAL-CLEAN|UNMEASURED|DIVERGENT|INSTRUMENT-DEFECT plus SKIPPED reason=rtk-absent when rtk isn't installed (exit codes: 0 clean-or-skipped, 1 divergent, 3 usage/env, 4 instrument-defect).

Footguns

  • rtk gain and rtk session show what rtk intercepted this session — the fastest way to prove a command was filtered. rtk discover lists commands it saw but did not filter.
  • Telemetry defaults (verified against RTK's README, 2026-10-13): rtk's telemetry is anonymous and off by default — opt-IN via rtk telemetry enable, not opt-out. Headroom's beacon is likewise off by default in current releases (their docs). Both are third-party claims about their own practices — re-check after upgrades.
  • rtk's hook emits its own permission decisions on some integrations — Soleur's guard judges the original command text either way (the two hook chains compose, not replace).
  • Proxy-layer filters see your API key and full prompt stream. Headroom's proxy mode — and any non-default ANTHROPIC_BASE_URL endpoint — sits on the credential path, not just the output path: your key and every prompt and tool result transit that infrastructure before reaching Anthropic. Read the vendor's privacy terms before installing a proxy-mode filter or pointing ANTHROPIC_BASE_URL at a third-party endpoint; a tool=proxy posture=unknown marker is Soleur telling you the transit exists, not judging it.
  • Reporting bugs: when filing, paste the full marker line into the bug report's marker field and answer the filter dropdown — triage applies the external-env label when it isn't none (don't add it yourself).

Stay in the loop

Monthly updates about Soleur — new agents, skills, and what we're building next.