Agent guards
Arcjet is a runtime security platform for AI agents. Agent guards check each action your agent or application takes against your policies before the action runs, and they record every decision so that you can see what happened and why.
An agent turns model output into real actions: it sends email, issues refunds,
queries databases, fetches URLs, and calls MCP servers. Those actions often run
inside a tool handler, a queue consumer, or a workflow step, with no HTTP
request for a firewall to inspect. The same applies to Arcjet’s own
protect() function, which checks
each HTTP request in your route handlers.
Agent guards cover those actions instead. Add a call to the Arcjet SDK’s
guard()
function immediately before the action, and pass it the values that matter,
such as the recipient, the amount, or the user. Arcjet evaluates the Guard
policy for that action and returns ALLOW or DENY. A Guard policy is the
set of rules for one action, which your security team publishes and changes in
the Arcjet Console without a deployment.
Capabilities
Section titled “Capabilities”Agent guards add the following controls to your own agents and applications:
- Deny an action based on application state that only your code knows, such as a refund over the user’s approval limit, an email to an external domain, a run that would exceed its spend budget, or a production change that nobody reviewed.
- Act on findings from Arcjet’s detectors, which screen a value for threats, such as prompt injection in the message that triggered the action or sensitive information in a body that’s about to leave.
- Screen sensitive information in your own process, so that the raw value never reaches Arcjet.
- Score the hosts that a tool would contact with Arcjet IP threat intelligence, and deny high-risk destinations.
- Rate limit actions per user, per tool, or per tenant, including actions that never arrive over HTTP.
- Change a policy without redeploying the application, and run each rule in dry run, which records what it would deny without denying it, before you set it live.
- Record each decision with the policy revision and the inputs it read, and record what an allowed action did afterward with capture events.
Use cases
Section titled “Use cases”Each use case in the following table links to a worked policy that you can adapt.
| Use case | Example policy |
|---|---|
| Let an email tool send only to approved domains | Restrict an email tool to approved domains |
| Stop customer data leaving in an external email | Keep sensitive data from leaving on an external send |
| Require approval for refunds over a limit | Keep a refund inside an approval limit |
| Refuse a destructive tool when the prompt shows injection | Act on a prompt injection finding in context |
| Restrict a web fetch tool to trusted hosts | Restrict a web fetch tool to trusted hosts |
| Deny requests to high-risk destinations | Deny a high-risk destination |
Block DROP and DELETE statements from a database tool | Deny a destructive database statement |
| Keep a file tool inside the workspace | Confine a file tool to the workspace |
| Allow only approved MCP servers | Restrict which MCP servers a tool can reach |
| Require a role before a privileged action | Require a role before a privileged action |
| Cap the spend of an agent run | Enforce a spend budget |
| Require review before a production change | Require review before a production change |
How it works
Section titled “How it works”┌──────────┐ guard() ┌──────────────┐ ALLOW ┌───────────────┐│ Agent or │──────────▶│ Guard policy │────────▶│ Action runs ││ workflow │ └──────┬───────┘ └───────────────┘└──────────┘ │ │ DENY ▼ ┌──────────────┐ │ Action stops │ └──────────────┘- You call
guard()immediately before the action, or wrap a tool with a framework integration, an Arcjet adapter for your agent framework that makes the call for you. The call names the action with alabel, such asemail.sent. It carries the actor, which is the user or service responsible, and the typed values that the policy reads, called inputs. - Arcjet selects the published policy for that label and evaluates it at the
edge, in the Arcjet region closest to
your application. An input that you mark
LOCALnever leaves your process, so the SDK evaluates it there. - Arcjet returns one
ALLOWorDENYdecision. Your code, or the framework integration, runs the action only onALLOW. A denied tool call returns a result the model can read. - Arcjet records the decision with the policy revision and the inputs it
read. It appears in the Console on the Activity page of your site, the
Arcjet project that your
ARCJET_KEYbelongs to.
For the full call, the decision fields, and fail behavior, see Agent guards testing and reference.
Labels and typed inputs
Section titled “Labels and typed inputs”A label is a stable, past-tense name for the action, such as email.sent or
refund.issued. It selects the policy, so one policy owns each action.
The application sends each value the policy reads as a named, typed input:
string, boolean, integer, number, or string list. A SERVER input is sent to
Arcjet for evaluation. A LOCAL input stays in the SDK, and only a digest and
the detector result leave your process. The actor is an identity your code
asserts from authenticated server-side state, never from the model. For the
full contract, see
Policy contract.
Detectors
Section titled “Detectors”A policy can declare Arcjet detectors and read their results as facts:
- Prompt injection, over a
SERVERstring. - Sensitive information, either in the SDK over a
LOCALstring or on Arcjet over aSERVERstring. - IP threat intelligence, over the hosts that a call would contact. For more information, see Threat detection.
A rule can deny on a finding alone, or combine it with application state, such as denying a destructive tool only when the triggering message shows prompt injection.
Guard policies
Section titled “Guard policies”You write a policy’s conditions in Rego, assemble them in the Console’s visual builder, or describe them in English and let Arcjet generate the builder rules. Arcjet runs a restricted Rego profile with no network calls, clock, or randomness, so the same inputs always produce the same answer. For the language, see Write policies in Rego.
Publication compiles the policy, runs its stored tests, and checks that the edge evaluator agrees with the Open Policy Agent evaluator before the policy goes out. For the authoring modes, tests, and revisions, see Author and publish policies.
You can also call SDK rules in code, such as rate limits, prompt injection
detection, and sensitive information detection, in the same guard() call. The
decision covers both.
Policy starting points
Section titled “Policy starting points”You don’t need to start from an empty policy. The policy examples cover common agent actions with complete Rego. In the Console, you can describe what an action must refuse, or take a suggestion that Arcjet derives from the input names and types your application already sends. Coding agent policies have their own one-click starters; for more information, see Coding agent policies.
Dry run, then live
Section titled “Dry run, then live”Each rule runs in LIVE or DRY_RUN mode. A dry run rule is evaluated and
recorded but never denies, and new rules default to dry run. Publish a rule in
dry run, review what it would have denied in the Console, and then set it live.
A live expression rule needs at least one stored test before it can be
published.
Agent guards and request protection
Section titled “Agent guards and request protection”Arcjet has two entry points, and they protect different boundaries:
| Agent guards | Request protection | |
|---|---|---|
| SDK call | guard() | protect() |
| Protects | Tool calls, agent actions, queue jobs, and workflow steps | HTTP routes and API requests |
| Selected by | The action’s label | Every protect() call on the site |
| Reads | The actor and the typed inputs you send, plus detector results | The request: IP, headers, path, and request signals |
| Remote configuration | Guard policies | Remote rules |
Most applications use both: request protection on their API routes, and agent guards inside the tool handlers, queue workers, and MCP tools behind them.
Supported SDKs
Section titled “Supported SDKs”Every SDK offers the direct guard() call and framework integrations that
place the same check around a tool for you.
| SDK | Package | Framework integrations |
|---|---|---|
| JavaScript/TypeScript | @arcjet/guard | Vercel AI SDK, LangChain, LangGraph, Genkit, Google ADK, Cloudflare Think, OpenAI Agents, Strands Agents, TanStack AI, Vercel Eve, Mastra, Claude Agent SDK, and Claude Managed Agents |
| Python | arcjet (arcjet.guard) | LangChain, CrewAI, Google ADK, OpenAI Agents, Strands Agents, Claude Agent SDK, and Claude Managed Agents |
| Go | github.com/arcjet/arcjet-go | Microsoft Agent Framework |
To pick an adapter and see how each SDK reports a denial, see Agent guard framework integrations.
Limitations
Section titled “Limitations”- The direct
guard()call fails open. If Arcjet can’t complete the check, it returnsALLOWmarked as failed open, so check for that before a sensitive action. Framework integrations fail closed by default. - A policy reads only what the call sends. A label that matches no published policy evaluates no policy. A missing required input fails a live rule closed, and an input the policy doesn’t declare is dropped with a warning. To avoid typos, generate the call from the policy in the Console.
- Arcjet doesn’t authenticate the actor. Derive it from your own authenticated session.
- A
LOCALinput’s digest is correlation data, not anonymization. A low-entropy value can be guessed and hashed.
For every fail behavior, see Availability and fail behavior.
Get started
Section titled “Get started”To start, guard one tool call end to end, and then publish your first policy in dry run.