feat(hook): wire TOML filters + better tee tail hint#2748
Conversation
…cation Wire TOML-covered commands into the transparent hook rewrite path, and make TOML truncation reversible via the shared tee hints. Part 1 — hook wiring (#2179): The hook's rewrite decision only consulted the static RULES table, so a command covered solely by a TOML filter (jj, jq, just, ssh, ty, nx, turbo, …) was passed through unfiltered by the hook even though `rtk <cmd>` filtered it directly. `rewrite_segment_inner` now consults the TOML registry on a RULES miss (Unsupported) and rewrites to `rtk <cmd>`, which re-enters via run_fallback → the TOML tier. Guards: honors RTK_NO_TOML, respects the exclude list, never rewrites Ignored (denylisted) commands, and a collision guard (is_rtk_reserved_command) prevents rewriting to a name Clap would route to its own subcommand. RTK_META_COMMANDS moved to core::constants as the shared source. Part 2 — reversibility: TOML truncation on success previously dropped lines with a bare "... omitted" marker and no recovery pointer. apply_filter_with_info now reports a Lossiness (Tail / Whole / None); run_fallback emits the line-offset tail hint (`[see remaining: tail -n +N …]`) for a contiguous tail-drop, the full-output hint otherwise, and — when tee is unavailable — shows the full raw rather than an unrecoverable marker. Fixes the symmetric <500B failure-path gap and an inaccurate MIN_TEE_SIZE comment in curl_cmd. All hosts (claude/gemini/copilot/cursor) and `rtk rewrite` are covered via the shared rewrite_command. No hook JSON / integrity-hash changes. The mirrored RULES rows are kept (they feed discover/session/gain metadata). Builds on the approach of #2226. Note: the TOML registry load now lands on the Unsupported hook hot path (~3-8ms native, one-time per process); the Supported path is unaffected. A match-only RegexSet to cut that cost is a documented follow-up. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…n flags Trust-gate both filter files; `rtk init` prompts to enable detected filters, or --trust-filters/--no-trust-filters for scripts.
Move the user-facing trust docs into docs/guide (config) and out of CODING_PRACTICES.
The warning printed to stderr on every rewritten command, adding tokens; trust is surfaced only in `rtk init`/`rtk trust`.
Concise filter list + [y/N] (--yes for non-interactive); drops the full-file dump and silent auto-trust. Shared prompt helper with init.
The rewrite path only needs a yes/no match, not the full compiled pipeline find_matching_filter forces on every not-in-RULES command (~10ms/call saved; selection still uses find_matching_filter in run_fallback).
Recoverable loss for a fired head/max cut (never a bare marker), schema-gate the hook match set, parse-error probe for trust; + tests.
…udly when non-interactive
pszymkowiak
left a comment
There was a problem hiding this comment.
Reviewed and verified locally (built from the branch): cargo fmt clean, cargo clippy --all-targets zero warnings, toml-orphan + trust tests pass.
Part 1 (hook wiring) — functional matrix confirms it: jj / jq / ssh / mise run / just / task rewrite to rtk …; absolute paths, redirects, compound (jj diff && jq . → rtk jj diff && rtk jq .), and env-prefix are preserved; cd / reserved / unknown commands are left alone; RTK_NO_TOML=1 disables the TOML fallback while keeping the static RULES.
Part 3 (trust gating) — verified end-to-end: an untrusted .rtk/filters.toml does not activate rewrites until rtk trust, then it does.
Part 2 (tee tail hint) — verified: truncated output carries [see remaining: tail -n +N <teefile>], following it recovers the omitted lines, and RTK_TEE=0 shows full raw with no truncation marker.
Security is sound: collect_match_patterns aggregates only trusted (SHA-256) + built-in filter patterns, so a malicious project filter can't inject a rewrite; reserved / rust-handled commands are excluded from the fallback.
Non-blocking nits: the tee file drops the final trailing newline, so hint recovery is byte-exact except that last \n (looks pre-existing). The ~3–8 ms one-time cost on the Unsupported path justifies the documented match-only RegexSet follow-up.
LGTM 👍

Summary
Wire TOML-covered commands into the transparent hook rewrite path, and make TOML truncation reversible via the shared tee hints.
Related issues & pr
ISSUES
#2179
#820
#2721
PRs
#2226
#894
#2722
#1068
Part 1: Hook wiring (#2179)
The hook only consulted the static
RULEStable, so commands covered solely by a TOML filter (jj,jq,ssh, …) weren't rewritten.rewrite_segment_innernow falls back to the TOML registry and rewrites them tortk <cmd>(guarded against denylisted/reserved names). Builds on #2226.Part 2: Reversibility
Truncated TOML output now carries a recovery hint: the line-offset tail hint (
[see remaining: tail -n +N …]) for contiguous drops, the full-output hint otherwise, and never an unrecoverable marker (falls back to full raw when tee is off).Then with the command hint

Part 3: Trust guards
Both the project
.rtk/filters.tomland the user-global~/.config/rtk/filters.tomlare now trust-gated (SHA-256).rtk initprompts to enable detected filters, or--trust-filters/--no-trust-filtersfor scripts.Note: the registry load now hits the hook's
Unsupportedpath (~3–8 ms, one-time per process; theSupportedpath is unaffected) , a match-onlyRegexSetis a documented follow-up."rtk init -g" (--trust-filters or --no-trust-filters available for non interactive)

"rtk trust" (--yes available for non interactive)

"rtk trust" on global + scoped config

Test plan
cargo fmt --all && cargo clippy --all-targets && cargo test— fmt clean, zero clippy warnings, 2310 unit + 8 integration tests pass (21 new tests added)rtk <command>output inspected — barejj log/stat /usr/bin/*/gcc --versiontransparently rewritten tortk …by the hook;stat/duemit[see remaining: tail -n +N …]and following it recovers the omitted lines byte-exact;RTK_TEE=0shows full raw with no truncation marker;git statusunchanged andcd/ reserved names /RTK_NO_TOML=1correctly pass through