· via dev.to (home feed)
OpenRouter's Armor guardrail vets agent tool calls, but Claude Code mode only flags them
OpenRouter's beta Armor classifier screens agent tool calls against plain-English rules before they run, but in Claude Code compatibility mode a flagged call still reaches the client, which must decline it itself.

OpenRouter launches a tool-call guardrail in beta
On October 15, OpenRouter put Armor into beta: a safety classifier that mediates between a model and the application driving it, evaluating every tool call against rules written in plain English before anything executes. A call that matches a rule is flagged, the model is told which rule it hit, and in most configurations the call never runs. Gabriel Anhaia's write-up on dev.to walks through the mechanics; GIGAZINE covered the launch on October 16.
One mode breaks that guarantee, and it is the detail anyone building agent pipelines should note.
How a verdict is produced
According to the Armor documentation summarized on dev.to, each tool call is sent to a decision model along with the configured rules and the conversation context. The model returns a probability that the call matches each rule, and Armor collapses those scores into a single verdict: flagged or not_flagged.
The launch post names the classifier as TypeSafe's Jev, a structured decision model that answers with typed results and probabilities rather than generated text; typesafe/jev-1.14 is listed as the current release. The pitch is that pattern and regex matching is often insufficient for catching unwanted tool calls, and OpenRouter also claims Armor outperforms Claude Code's built-in auto-mode classifier on both performance and cost. A review on explainx.ai notes that no test set or benchmark numbers have been published to support that comparison, and the dev.to author has not run Armor himself.
Three tiers of rules
Rules fall into three tiers:
- hard_deny covers actions that should never proceed, no matter what the user asks for.
- soft_deny covers actions that are typically wrong but occasionally requested on purpose; a match is blocked unless an allow rule also fires or the user explicitly asked for that exact operation on that exact target during the conversation.
- allow never blocks anything; it carves out exceptions to soft-deny rules.
Armor additionally enforces a built-in soft-deny for limits a user has stated in conversation and not yet lifted, such as a request not to push until review. Rules carry an id, an optional name, instructions and an optional threshold, with defaults of 0.6 for deny rules and 0.7 for allow rules. An audit mode scores everything and enforces nothing, letting teams tune rules against real traffic before switching enforcement on; it cannot be combined with Claude Code compatibility mode.
Where a blocked call lands
Three output modes determine what a block looks like. With text, the default on Chat Completions and Responses, the blocked call is replaced by a marker in the assistant text; with custom_item on the Responses API, it becomes an openrouter:armor_blocked output item. In both cases the call never reaches application code, and the model is told the call was blocked and should not be retried with the same arguments.
The third mode, claude_code_compatibility, applies to the Messages API and is selected by a safeguards entry of type dangerous_tool_use rather than a plugins entry. Here the flagged tool_use stays in the response, marked in a safeguard_results array, and enforcement moves to the client. The docs are blunt about the consequence: a Messages client that ignores safeguard_results will execute a flagged call. If a client may not check, the docs recommend output_mode text instead. Claude Code itself handles this correctly, declining the call and returning an is_error tool result; the exposure is a hand-written Messages client that never reads the verdict.
Failure modes and limits
When the decision model times out, errors or receives a request too large to judge, the verdict is unavailable. For plugin requests, on_error decides between block, the default, and log. In Claude Code mode that setting does not apply: unavailable calls are always released with the verdict visible, leaving the decision to the client.
Other documented limits: Armor is not yet available for HIPAA, Zero Data Retention or data-region-restricted requests. Plugin requests there are rejected with a 403, while Claude Code requests are released with an unavailable verdict and fall back to Claude Code's local auto-mode check, meaning Armor is not screening those calls today. The decision model can produce false positives and misses, with the per-rule threshold as the tuning knob. With the Claude Code-compatible rule set loaded, median latency rose 279 ms per tool call, and 334 ms at the 90th percentile, a cost an agent turn pays on every call it fires. Evaluation is free during the beta, pricing is due before general availability, and the configuration fields, the safeguard_results object and the openrouter:armor_blocked item type may still change.
Why it matters
Agent pipelines increasingly hand models shell and filesystem access, and a guardrail that intercepts tool calls server-side closes a gap that client-side checks leave open whenever a bug or a custom client skips them. Armor's default design keeps enforcement upstream of the application; its Claude Code compatibility mode deliberately hands that responsibility back, because Claude Code is a client known to honor verdicts. Anyone pointing a homemade Messages client at that endpoint inherits the job of reading safeguard_results, along with per-call latency and a beta-era API surface that OpenRouter says may still shift.
- #openrouter
- #ai-agents
- #guardrails
- #tool-calls
- #claude-code