Tool Substitution
When the agent uses a legacy CLI tool, Warden transparently swaps it for a modern, faster alternative. The agent never knows the substitution happened — it just gets faster results.
| Agent uses | Warden runs | Why |
|---|---|---|
grep | rg (ripgrep) | 10-50x faster regex search |
find | fd | Faster file discovery with sane defaults |
curl | xh | Friendlier HTTP client |
cat | bat | Syntax highlighting, line numbers |
ls | eza | Better directory listings with git status |
du | dust | Visual disk usage tree |
tar/zip | ouch | Auto-detecting archive tool |
sort|uniq | huniq | Faster, preserves order |
ts-node | tsx | Faster TypeScript execution |
Substitutions only fire when the target tool is installed. The warden init wizard detects and offers to install missing tools.
Why Substitutions Exist
AI agents default to the tools they’ve seen most in training data. That means grep, find, curl, and cat — tools designed in the 1970s-90s. Modern alternatives are faster, produce less output (saving context tokens), and have better defaults for the kinds of searches agents perform.
The agent doesn’t need to know about rg or fd. It writes the command it knows, and Warden intercepts the call at the hook level. The deny message tells the agent to use the modern tool instead, and since agents self-correct after denials, the substitution sticks for the rest of the session.
Before and After
grep vs rg — The agent searches for a function name across a large codebase:
# What the agent writes:
grep -r "handlePayment" --include="*.ts" src/
# What Warden tells the agent:
BLOCKED: Use rg (ripgrep) instead of grep. Same flags: rg PATTERN [PATH].
# What the agent runs next:
rg "handlePayment" src/ -t ts
The rg version is 10-50x faster, respects .gitignore by default (no node_modules noise), and produces a cleaner output format that consumes fewer context tokens.
find vs fd — The agent looks for config files:
# What the agent writes:
find . -name "*.config.js" -type f
# What Warden tells the agent:
BLOCKED: Use fd instead of find. Example: fd PATTERN [PATH]. Regex by default.
# What the agent runs next:
fd "\.config\.js$"
fd ignores hidden files and .gitignore patterns by default, uses regex, and produces colored output with less noise.
cat vs bat — The agent reads a source file:
# What the agent writes:
cat src/main.rs
# What Warden tells the agent:
BLOCKED: Use bat instead of cat. Example: bat FILE (syntax highlighting).
# What the agent runs next:
bat src/main.rs
bat adds line numbers and syntax highlighting, making the output more useful for the model to parse. It also handles large files better with built-in paging.
Availability Check
Substitutions are not unconditional. Before denying a grep call, Warden checks whether rg is actually installed on the system. If the target tool isn’t available, the substitution rule is skipped and the original command runs normally.
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/config.toml:
[restrictions]
disabled = ["substitution.0"] # Stops redirecting grep → rg
Use warden describe --all to see the full list of substitution rule IDs:
| Rule ID | Substitution |
|---|---|
substitution.0 | grep to rg |
substitution.1 | find to fd |
substitution.2 | curl to xh |
substitution.3 | ts-node to tsx |
substitution.4 | du to dust |
substitution.5 | sort|uniq to huniq |
substitution.6 | sd blocked (Windows) |
substitution.7 | tar to ouch |
substitution.8 | zip to ouch |
substitution.9 | unzip to ouch |
substitution.10 | gzip to ouch |
substitution.11 | cat to bat |
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.