Warden
beta · v4.12.0
beta · v4.12.0
Documentation

Tool Substitution

When the agent reaches for a legacy CLI tool, Warden can either rewrite the command to a modern alternative or teach the agent to use it. The result is faster execution, less noisy output, and better defaults.

Agent usesWarden runsWhy
greprg (ripgrep)Faster regex search; skips .gitignored paths, so less output
findfdFaster file discovery with sane defaults
curlxhFriendlier HTTP client
catbatSyntax highlighting, line numbers
lsezaBetter directory listings with git status
dudustVisual disk usage tree
tar/zipouchAuto-detecting archive tool
sort|uniqhuniqPreserves insertion order
ts-nodetsxFaster TypeScript execution
sdBlocked on Windows: mangles newlines and encodings

Substitutions only fire when the target tool is installed. The warden init wizard detects and offers to install missing tools.

Eleven built-in rewrite rules back this table. Seven are structured — they parse the command, swap the program, and translate flags: grep, find, cat, curl, ls, du, plus an rg --includerg -g fixup. Four are standalone rules: ts-nodetsx, the archive tools → ouch, sort | uniqhuniq, and the Windows sd block.

Each rule resolves to one of three outcomes. Teach leaves the command alone and tells the agent the modern equivalent. Apply rewrites the command in place, mapping the flags across. Deny blocks it outright — sd on Windows is the only built-in that does this. ls, du, the rg --include fixup, and plain ts-node invocations apply; the rest teach. Change the default with [rewrite] default_mode, or override one rule:

# ~/.warden/rules.toml
[rewrite]
default_mode = "teach"   # or "apply_if_possible"

[[rewrite.rules]]
id = "grep-rg"
mode = "apply_if_possible"

Why Substitutions Exist

AI agents default to the tools they’ve seen most in training data — grep, find, curl, cat. Modern alternatives are faster, produce less output (saving context tokens), and have better defaults for the kinds of searches agents perform.

Warden intercepts the call at the hook level and either rewrites it directly or names the modern equivalent alongside the result. Agents pick the replacement up and keep using it for the rest of the session. This isn’t about tool ideology — it’s about practical outcomes: faster results, less context waste.

Before and After

grep vs rg — a teach rule. The agent searches for a function name across a large codebase:

# What the agent writes:
grep -r "handlePayment" src/

# What Warden attaches to the result:
Structured rewrite [grep-rg]: consider using `rg "handlePayment" src/` instead.

# What the agent runs next:
rg "handlePayment" src/ -t ts

The command still runs; the hint travels back with it. The rg version is faster, respects .gitignore by default (no node_modules noise), and produces a cleaner output format that consumes fewer context tokens. Agents pick up the substitution and keep using it for the rest of the session.

ls vs eza — an apply rule. Nothing is said at all:

# What the agent writes:
ls -la src/

# What actually runs:
eza --long --all src/

Flags are translated by the rule’s flag map — -la to --long --all, -R to --tree, -1 to --oneline. The agent sees only the output.

sd on Windows — a deny rule. The command is blocked and the agent is told what to use instead: the Edit tool, which preserves line endings and encoding.

The rg --include fixup is worth calling out separately: it rewrites rg --include=GLOB to rg -g GLOB, correcting a flag agents routinely carry over from grep.

Availability Check

Substitutions are not unconditional. Before acting on a grep call, Warden checks whether rg is actually installed. If the target tool isn’t available, the rule is skipped and the original command runs untouched — a rewrite to a missing binary breaks the command, and a hint pointing at one is noise.

Availability is probed from PATH and cached, and the cache is re-taken daily.

The warden init wizard detects which modern tools are missing and offers to install them via cargo install or your system package manager. You can also install them manually at any time — Warden will start using them on the next session.

Disabling Specific Substitutions

If a substitution doesn’t fit your workflow, disable it by rule ID in ~/.warden/rules.toml:

[restrictions]
disable = ["substitution.grep"]  # Stops redirecting grep → rg

Substitutions are one of the two namespaces a project-level .warden/rules.toml may also disable (the other is advisory.), so a repo can opt out for its whole team.

The ID is substitution. plus the command being replaced. There are eleven registered:

Rule IDSubstitution
substitution.grepgrep to rg
substitution.findfind to fd
substitution.curlcurl to xh
substitution.catcat to bat
substitution.ts-nodets-node to tsx
substitution.lsls to eza
substitution.sdsd blocked (Windows)
substitution.dudu to dust
substitution.tartar, zip, unzip to ouch
substitution.sortsort | uniq to huniq
substitution.rgrg --include to rg -g

Run warden --debug restrictions list --category Substitution to print the same list from the binary.

Every ID in the table above is honoured, as are any substitution patterns you add in rules.toml. A substitution is also skipped when its replacement isn’t installed — Warden never rewrites grep to rg on a machine without rg.

Windows Note: sd Is Blocked, Not Substituted

On Windows, sd (the sed replacement) is blocked entirely rather than substituted. It mangles line endings and file encodings on Windows. Warden’s deny message directs the agent to use the Edit tool for file modifications instead, which preserves encoding correctly.