Steer: Deny or rewrite an AI agent's tool calls before they run Steer, a new rule engine for AI agents, intercepts and can deny, rewrite, or annotate tool calls before execution, with rules defined in TOML files. It addresses the problem that Claude Code's auto mode injects system directives that override user settings, making hooks the only layer with final control. The tool, installable via cargo, includes built-in rules, supports global and project-level configs, and evaluates rules to apply the strongest action (deny > rewrite > context). A rule engine that sits in front of an agent's tool calls. It sees each call before it runs and either denies it with guidance the model reads, rewrites its input in place, or lets it through with context attached. Rules live in TOML, so redirecting a new tool is a config entry rather than another branch in a growing shell script. It exists because a harness can outrank you. Claude Code's auto mode injects a system directive to search with shell grep and read with sed -n ; it beats anything in CLAUDE.md , and no setting turns it off. A hook is the last layer that still gets to decide. bash $ steer check 'cd build && rm -rf dist' command cd build && rm -rf dist segments head=cd args= "build" pipeline start=true depth=0 head=rm args= "-rf", "dist" pipeline start=true depth=0 matched trash-over-rm action rewrite rewrite cd build && trash dist cargo install --path . --root ~/.local Then register it in ~/.claude/settings.json : { "hooks": { "PreToolUse": { "hooks": { "type": "command", "command": "steer hook --event PreToolUse" } } } } No config file is needed. The built-in rules are compiled into the binary and active on install. Register PostToolUse the same way once you have a context rule for it. None of the built-ins are, so adding it before then spends a process launch on every tool result and changes nothing. Rules come from three places, each stacking on the one before: Built-ins , compiled into the binary and active with no config file at all.— your base, the one to keep in dotfiles. Honors ~/.config/steer/config.toml $XDG CONFIG HOME . steer init writes a commented starter here., found by walking up from the session's working directory — whatever this one project needs. .steer.toml in the repo A later source replaces an earlier rule of the same name, and disable switches one off wherever it came from: .steer.toml — no fff index in this repo, but psql reaches a live database disable = "fff-over-grep" rules name = "no-prod-psql" tool = "Bash" rules.match any = "parsed.segments" head = { any of = "psql" } rules.action kind = "deny" message = "Use the read replica: psql -h replica.internal." What a repo file cannot do is quietly soften a rule it does not name. Every matching rule is evaluated and the strongest action wins, so putting a context rule beside an inherited deny still denies. Switching one off takes disable , by name, in the open. steer validate reports unknown fields, bad globs and regexes, duplicate rule names, and a disable naming a rule nothing defines — with file and line. steer hook --event PreToolUse|PostToolUse read a hook payload on stdin, decide on stdout steer check '