Skip to content
←Back to Blog
Hugging Face SafeAgents: A Deterministic Gate Before Tool Calls Reach Runtime
Agent SecurityTool Call FilteringEmbodied AI

Hugging Face SafeAgents: A Deterministic Gate Before Tool Calls Reach Runtime

A technical guide to SafeAgents' declared-tool policy, ATIF scanning, and optional judge, and the runtime, sandbox, and robot safety layers it does not replace.

Cobus Greyling / Hugging FaceNovember 9, 202617 min read29 views
ZH

The dangerous output of an agent is often not prose. It is a tool call. A model can explain why it wants to inspect a file, install a package, fetch a URL, or run a shell command without doing any of those things. The harness is the component that turns that proposal into an effect. Hugging Face SafeAgents, or HFSA, inserts a filter at exactly that handoff: model response in, proposed tool calls checked, and only the surviving calls released to the harness.

This is a narrower idea than “agent security,” and that narrowness is its main strength. SafeAgents is not another agent framework, an execution sandbox, or a replacement for operating-system controls. It is a local reverse proxy that observes model traffic and rewrites blocked calls before the client receives them. The project supports OpenAI Chat Completions and Anthropic Messages. It does not yet inspect tool calls carried by the OpenAI Responses API or the Gemini API, which means current Codex CLI and Gemini CLI traffic can pass through without the intended call-level protection.

Cobus Greyling’s article presents the system as three layers: a request-only policy, deterministic scanning with atif-scan, and an optional model judge. The first two carry most of the security value. The judge can add a block, but it cannot overrule a deterministic one. That ordering matters. A probabilistic component is useful at the edge of ambiguity; it should not be allowed to erase a clear, reproducible finding.

SafeAgents proxy between an agent harness and a model server, with deterministic checks, atif-scan, an optional judge, tools, and logs
Figure 1 | The proxy sits on the response path. The harness sends a request through SafeAgents to the model. The response is held at the proxy, its proposed tool calls are checked, and blocked calls are replaced with a notice. Image source: Cobus Greyling.

The relevant architecture can be stated in one sentence: SafeAgents filters proposed actions at the model boundary, while the runtime must still govern the effects of actions that are allowed through. That distinction becomes especially important when the harness can drive a robot simulator, ROS bridge, shell, deployment script, or physical controller. A policy at the model boundary can remove an obviously bad request; it cannot certify that every approved motion command is physically safe.

1. Where SafeAgents sits

The installation model is intentionally uncomplicated. Start the proxy against the model server the harness normally uses, then change the harness base URL to the local proxy. In the project’s Anthropic example, the harness talks to http://127.0.0.1:8787, and SafeAgents forwards traffic to https://api.anthropic.com. The harness and model do not need to implement a new safety protocol. The proxy parses the existing request and response formats.

The timing is important. Every complete tool call is reviewed before the harness sees the model response. A blocked call is not merely logged after execution; it is replaced by a text notice, so the harness receives no callable instruction to run. Plain text streams through as it arrives. A streaming tool call is held only until its arguments are complete, because the arguments are the object that must be scanned. Responses that are not changed can be forwarded byte for byte.

That design also defines the product’s boundary. SafeAgents does not execute tools, sandbox a process, grant capabilities, or restrict network access at the operating-system level. It is a policy gate over proposed calls. The harness remains responsible for execution, and the surrounding system remains responsible for isolation, resource limits, audit retention, credentials, and human approval.

Video 1 | Calls move from pass to warning to block. The demonstration places 16 harnesses behind the proxy and shows live verdicts. Ambiguous findings can be warned while high-severity findings are blocked. Source: Cobus Greyling and the SafeAgents project.

The protocol limit is not a footnote. A proxy that forwards traffic without understanding the location of a tool call has not established a tool-call boundary. The repository explicitly marks Codex CLI’s Responses API and Gemini CLI’s Gemini API as unsupported for inspection. Using the proxy in that configuration may still provide routing and logging, but the central protection is absent. Any deployment should fail visibly when the harness protocol is outside the supported set.

2. The three checks are not interchangeable

2.1 Request-only policy: what was actually authorized?

The first check needs only the incoming model request. It blocks a tool name that the request never declared. It also extracts complete URLs and bare IPv4 addresses from the proposed arguments and blocks a host that appears neither in trusted conversation context nor on an explicit allowlist. Assistant messages are removed before the host context is built. Otherwise a model could mention an attacker-controlled host in one turn and cite its own sentence as authorization in the next.

This is a small, legible capability system. It does not attempt to understand every command. It asks two deterministic questions: is this the tool interface the caller declared, and did the destination come from somewhere other than the model’s own output? The host check is particularly useful against exfiltration attempts where an otherwise legitimate shell tool is asked to send data to an address that no user or system instruction supplied.

2.2 atif-scan: deterministic evidence over the trajectory

The second layer converts the conversation and the pending tool call into an Agent Trajectory Interchange Format trace. atif-scan then evaluates deterministic detectors and context-sensitive rules. SafeAgents keeps only findings whose evidence points at the pending call. Reasoning is deliberately excluded from the trace used for this decision; the model’s account of why it acted is not evidence of what the call will do.

Findings at or above the configured block severity, high by default, are rejected without asking another model. Lower-severity findings mark the call as suspicious. With no judge configured, suspicious calls are logged and allowed. That default is important to understand: the system is a hard blocker for its highest-priority rules, not a universal “review every medium finding” gate.

The scanner is static only in the runtime sense. Its checks do not learn during a run. The rule library is actively maintained. Greyling reports 358 commits in about seven weeks and release v0.8.21 at the time of writing. A later repository audit found 360 commits and v0.8.22, with the SafeAgents dependency requiring atif-scan>=0.8.15. The author also reports 10–20 ms scanning overhead per call on an M-series Mac. Those figures are useful operating claims, not an independent benchmark for every model, CPU, trace length, or policy pack.

2.3 A judge that can say no, but not yes

The optional judge receives the latest user request, the tool call, and the scanner findings. It does not receive the system prompt, the agent’s reasoning, or prior tool results. The omission is intentional: a compromised or goal-seeking agent should not get to explain why its suspicious call is acceptable. The judge returns a constrained allow or block decision. It can add a block to a suspicious call. It cannot remove a deterministic block.

Judge failures also need a policy. SafeAgents defaults to fail open: if the judge is unavailable or returns no usable verdict, the suspicious call is allowed and logged. Operators can opt into fail closed. That choice should follow the consequence of the action. For a documentation summarizer, a brief judge outage may be tolerable. For a process that can move a robot, alter a production deployment, or expose credentials, an unavailable review layer should normally stop the high-consequence path.

The decision path for each completed tool call
Stage Question Default effect Failure mode to understand
Request-only policy Was the tool declared, and did the target host come from trusted context or the allowlist? Block immediately. It checks host selection, not whether an approved host or command is harmless.
atif-scan Do deterministic rules find evidence of a known misuse pattern in the trace? Block at or above high; mark lower findings suspicious. Unknown patterns remain unknown, and scanner exceptions currently fail open.
Optional judge Given only the user task, call, and findings, should this suspicious call still run? Allow or add a block. No judge means log and allow; judge failure is also open unless fail-closed is enabled.
Harness runtime Can the approved action execute with the current process, filesystem, network, and device permissions? Outside SafeAgents. This is where a sandbox, capability system, interlock, rate limit, and human sign-off belong.

3. Why deterministic checks carry the weight

A deterministic finding is inspectable. An operator can identify the rule, see the evidence, pin the scanner version, and reproduce the result. A model judge has a different role: it resolves ambiguity after the deterministic layer has already narrowed the case. Putting the judge first would make the entire policy stochastic and much harder to audit.

The source article calls atif-scan the real power behind the proxy. That is a useful emphasis, but not because pattern matching is sufficient by itself. The strength is the combination of cheap rejection rules with a growing library of context-aware checks. For example, a credential finding can depend on whether a secret was actually exposed, and an allowance can distinguish a package install required by the task from an unrelated lure. These are not merely regular expressions over a single command.

The limitation is equally clear: the scanner catches what its rule library represents. Novel misuse, a semantically dangerous action built from apparently ordinary commands, or an unsafe domain-specific operation may pass. The proxy therefore works best as a high-confidence tripwire that buys time and evidence, not as a proof that the remaining action is safe.

ATIF scan repository page showing deterministic detectors, trajectory inputs, findings, allowances, and release activity
Figure 2 | The scanner is broader than a flat command blocklist. The repository describes offline trajectory analysis, context-aware integrity checks, benchmark-awareness detectors, and task-specific allowances. Findings are review candidates, not automatic proof of malicious intent. Image source: Hugging Face atif-scan repository.

Operational logging also changes the safety posture. SafeAgents can run with --log-only, which reports what it would block without altering the response. This is the right first deployment for an unfamiliar harness. It lets an operator learn the false-positive profile and the actual host and tool vocabulary before the proxy begins replacing calls. The journal stores blocked, flagged, and suspicious calls with their arguments, which can contain secrets, so the file permissions and retention policy are part of the security design.

4. Reading the synthetic ATIF example

The article includes a deliberately synthetic trace. It represents a benchmark task with three shell calls: list the tests, install a package, and run the tests. No benchmark data or credentials are used. The important point is that the scanner sees the trajectory and the proposed calls together, rather than judging a command as an isolated string.

{
  "schema_version": "ATIF-v1.7",
  "steps": [
    {
      "step_id": 1,
      "timestamp": "2026-01-01T00:00:00Z",
      "source": "user",
      "message": "Synthetic fixture: no benchmark data or credentials."
    },
    {
      "step_id": 2,
      "timestamp": "2026-01-01T00:00:07Z",
      "source": "agent",
      "message": "This is a benchmark task. All tests passed.",
      "tool_calls": [
        {
          "tool_call_id": "synthetic-call-1",
          "function_name": "Shell",
          "arguments": { "command": "ls /tests" }
        },
        {
          "tool_call_id": "synthetic-call-2",
          "function_name": "Shell",
          "arguments": { "command": "pip install requests" }
        },
        {
          "tool_call_id": "synthetic-call-3",
          "function_name": "Shell",
          "arguments": { "command": "pytest -q" }
        }
      ],
      "observation": {
        "results": [
          { "source_call_id": "synthetic-call-1", "content": "Synthetic result only." },
          { "source_call_id": "synthetic-call-2", "content": "Synthetic result only." },
          { "source_call_id": "synthetic-call-3", "content": "Synthetic result only." }
        ]
      }
    }
  ]
}

The report separates behavioural findings from telemetry uncertainty. The access.test_path finding is medium severity, awareness.benchmark is low, and network.package_install is informational. Seven integrity checks remain unresolved because the synthetic trace does not record the model stop reason or enough usage accounting to settle them. The score of 50 is the highest unexcused match in this example; the report frames findings as review candidates, not verdicts.

ATIF scan output showing a score of 50, medium, low, and informational findings, and seven unresolved telemetry checks
Figure 3 | Severity and confidence are separate concepts. The output distinguishes a medium behavioural finding from low awareness signal, informational package activity, and missing telemetry. Image source: Cobus Greyling.
atif-scan 0.8.21

input-0001 score 50 (medium) · behavioural coverage complete · telemetry checks unresolved
agent steps 1 · tool calls 3 · unrecognized tool calls 0
ending not known: the harness does not record model stop reasons
status  check                    evidence / reason
medium  access.test_path         step 2 call 0 command
low     awareness.benchmark      step 2 message
info    network.package_install  step 2 call 1 command
Telemetry checks unresolved (7 checks): integrity.cached_tokens_exceed_prompt,
integrity.cost_missing, integrity.output_token_ratio,
integrity.reasoning_tokens_exceed_completion, integrity.step_count_mismatch,
integrity.tokens_exceed_recorded_calls, integrity.totals_are_last_call
101 no match · 4 not applicable

1 input(s) · 1 available · 0 behavioural coverage incomplete · 1 telemetry
checks unresolved. Findings are review candidates, not verdicts; unknown checks
remain unresolved.

This example is a useful antidote to binary security dashboards. “No high finding” does not mean complete evidence. “Score 50” does not mean the trace was malicious. A mature deployment distinguishes the absence of a match from unavailable telemetry, incomplete capture, and a rule that the scanner could not evaluate.

5. Six security layers, one of which SafeAgents provides

The most common mistake after reading a project like this is to compress several independent controls into the phrase “SafeAgents protects the agent.” It does not. It provides one policy layer. The following table keeps the layers separate.

Controls that solve different problems
Layer Question it answers Typical mechanism SafeAgents coverage
Tool-call policy Should this proposed call leave the model boundary? Declared-tool checks, host provenance, deterministic detectors, optional judge. Yes. This is the core function.
Execution isolation What can the harness or tool process do after the call is allowed? Containers, VMs, seccomp, namespaces, privilege separation. No.
Filesystem and device authority Which files, serial ports, cameras, actuators, or PLC endpoints can be reached? OS users, mount policy, device permissions, capability lists. No.
Network egress Which destinations can receive traffic after a call is approved? Firewall, proxy allowlist, DNS policy, service mesh, network namespace. Partial at proposal time; not an egress enforcement layer.
Physical safety Is this torque, velocity, workspace, or state transition safe right now? Watchdogs, limits, certified controllers, emergency stops, independent interlocks. No.
Identity and accountability Who authorized the action, under which policy, and what happened afterward? Scoped credentials, approval chain, append-only audit, trace retention. Partial logging; not an identity or approval system.

The project itself uses the phrase “a local proxy,” not “a sandbox.” It says plainly that it filters what the model asks for before the harness acts. That makes it complementary to a runtime boundary such as a container, a permission system, or an actuation safety controller. The correct deployment claim is therefore precise: SafeAgents reduces the set of model-proposed actions that reach the runtime; it does not guarantee that every remaining action is safe or authorized.

6. Why this matters for embodied AI

Robot-agent systems increasingly place a language or multimodal model above a tool layer. That layer may call a simulator, query a robot state service, publish a ROS message, run a motion-planning CLI, inspect a camera stream, update a deployment manifest, or invoke a vendor API. In many prototypes, the same harness also has shell access, cloud credentials, and a filesystem. A single unexpected tool call can therefore cross from text generation into code execution or equipment control.

SafeAgents can sit beneath such a harness if the model protocol is supported. The request-only policy can reject an undeclared actuator tool or a destination that no trusted instruction supplied. atif-scan can catch known dangerous patterns, and a task-specific plugin can encode local policy. The judge can receive the current instruction, call, and findings for a second review when the deterministic evidence is ambiguous.

For a robot, “the tool call was allowed” is not the same statement as “the physical action is safe.” The first is a software policy decision. The second requires a runtime that knows state, limits, timing, and consequences.

SafeAgents has not been validated on physical robot stacks. It does not know joint positions, force limits, collision geometry, controller mode, emergency-stop state, or whether a simulator is connected to hardware. A robot deployment must keep those checks in the controller and safety path, independent of the language model and of the model-boundary proxy. For high-consequence tools, use a dry run or shadow mode, require a separate approval service, and preserve the complete call and verdict record.

The most realistic early use is development and operations rather than direct actuation. Put the proxy in front of a coding agent that edits robot software, changes simulator configuration, or prepares a deployment. Run it in --log-only mode first, audit the calls, then constrain the hosts and tools and move only selected workflows into blocking mode. Keep physical actuation behind a separate, deterministic safety layer even when the same agent is allowed to prepare commands.

7. A deployment checklist

  1. Inventory every model path. Route all subagents, title generators, compaction calls, and tool-using models through the supported proxy formats. A single unsupported Responses or Gemini path bypasses call inspection.
  2. Start in log-only mode. Collect the real tool set, destination hosts, medium findings, false positives, and judge behavior before changing response bodies.
  3. Pin versions. Record the SafeAgents commit, atif-scan version, plugin code, model judge, prompt, and severity threshold. A changing rule library should be treated like changing security software.
  4. Make failure behavior explicit. Decide whether scanner exceptions and judge outages should fail open or closed for each class of action. The defaults are not suitable for every consequence.
  5. Define the allowlist narrowly. Review hosts and tools per task. Do not let the model’s own earlier text become host authorization, and do not rely on a broad shared allowlist for unrelated workflows.
  6. Keep execution isolated. Run the harness with the least filesystem, network, credential, and device authority it needs. Filtering a call does not make a privileged executor safe.
  7. Protect the journal. Tool arguments can contain secrets. Restrict permissions, rotate exposed credentials, define retention, and separate audit access from the agent’s own access.
  8. Test the negative path. Prove that a blocked call never reaches the harness, that an unsupported protocol is visible, that judge failure follows policy, and that log-only mode changes reporting without changing execution.
  9. Keep a physical safety chain. Robot controllers, workspace limits, watchdogs, interlocks, and emergency stops remain independent of the LLM proxy.

8. Assessment

SafeAgents is a good example of a security layer with a clear interface. It does not try to solve the entire agent problem. It places a deterministic first line at the point where model text becomes an executable proposal, gives the operator a visible decision trail, and adds a constrained judge only after the evidence is already suspicious.

Its weaknesses are equally legible. Protocol coverage is incomplete. Low-severity findings pass by default without a judge. Scanner errors and judge failures can fail open. The policy can enforce known tool and host constraints but cannot establish the safety of an unknown command, the integrity of the harness, or the physical suitability of an action. The project is young, and the rule library changes quickly, which makes version pinning and regression testing essential.

The right conclusion is not that SafeAgents makes agent systems safe. It is that model-facing tool policy deserves its own boundary, separate from execution isolation. For embodied AI, that separation is especially valuable: the language model may propose an action, the proxy may reject a known bad proposal, and the robot runtime must still decide whether the remaining action is physically valid. Each layer should be able to say no on its own.

Repository audit note: this article inspected huggingface/safeagents at commit 2a178aacb74fe386667956d825fed49453823f70 and huggingface/atif-scan at commit 1d64be4b491c1fb62c5dfce6c4a3fd766b94867a. SafeAgents declared version 0.0.1 and required atif-scan>=0.8.15; the inspected scanner version was 0.8.22. Performance and change-rate figures attributed to the author remain author claims rather than independently reproduced benchmarks.

Source: “HuggingFace Safe Agents” by Cobus Greyling, published November 9, 2026. Project sources: Hugging Face SafeAgents and ATIF Scanner.

As an Amazon Associate, we earn from qualifying purchases.