Agent get started
Arcjet is the AI agent runtime security platform. Discover the agents running in your organization, enforce policy across every action, prompt, and tool call, and keep the evidence to prove what happened. Detect prompt injection, authorize agent tool calls, redact PII, and block bots and abuse.
Agents can register on behalf of the user using agent registration.
Choose an integration path
Section titled “Choose an integration path”Read this section first and skip to the path that matches the project. Most projects need one.
| What you’re protecting | Path |
|---|---|
| A developer’s coding agent (Claude Code, GitHub Copilot, OpenAI Codex, Cursor) | Secure the coding agent. No package to install. |
| An agent you built (tool calls, MCP servers, queue workers) | Guard with @arcjet/guard or arcjet.guard. |
| HTTP routes and API endpoints | Protect with a request SDK. |
Detect which one applies by reading the project manifest:
package.jsonwithnext,express,fastify,@nestjs/core,@sveltejs/kit,hono,@remix-run/node,react-router,astro, ornuxt, or a Bun or Deno runtime, means a web application.pyproject.tomlorrequirements.txtwithfastapiorflaskmeans a web application.go.modmeans the Go SDK withnet/httpor any router that exposes*http.Request.- An agent framework in either manifest (
ai,eve,genkit,langchain,@langchain/langgraph,@mastra/core,@openai/agents,@google/adk,google-adk,@cloudflare/think,@strands-agents/sdk,@tanstack/ai, orcrewai) means the project builds its own agent. Use the guard adapter for that framework, instead of or alongside a request SDK.
Two package names look alike and are different products. @anthropic-ai/sdk or
anthropic calling hosted sessions and events.send is Claude Managed
Agents. @anthropic-ai/claude-agent-sdk or claude-agent-sdk with a local
query() loop is the Claude Agent SDK.
Protect compared with Guard
Section titled “Protect compared with Guard”| Protect (request SDKs) | Guard (@arcjet/guard, arcjet.guard, NewGuardClient) | |
|---|---|---|
| Designed for | HTTP route handlers, API endpoints | AI tool calls, MCP servers, queue workers, background jobs |
| Request object | Required | Not needed |
| Rate limit key | IP or characteristics | Explicit key string at call time |
| Rate limiting / prompt injection / sensitive info | ✅ | ✅ |
| Bot protection / Shield / email validation / filters / IP analysis | ✅ | – |
| Content moderation | – | ✅ |
| Custom rules | – | ✅ |
A single application can use both: request-based protection on API routes, and guards inside tool handlers, queue workers, and MCP tools.
Install a skill
Section titled “Install a skill”Skills are the primary entry point for setting up Arcjet in an agentic workflow. They give your agent the documentation to detect the framework, install the SDK, and wire up protection rules.
npx skills add arcjet/skillsThen describe what you want to protect. The skill handles the rest. For the source, see github.com/arcjet/skills.
Connect to the Arcjet API
Section titled “Connect to the Arcjet API”Skills handle the SDK and rule integration in your code. To create sites,
retrieve ARCJET_KEY, inspect requests, and manage remote configuration, the
agent needs to talk to the Arcjet API. There are two transports:
- Arcjet CLI for agents and humans working in a terminal (Claude Code, Codex, plugin tasks, CI). No editor or MCP setup required.
- MCP server for online clients without shell access (ChatGPT, Claude Desktop) and clients with built-in MCP support (Claude Code, Codex CLI, Cursor, VS Code with Copilot, Windsurf).
The two transports overlap but aren’t identical. Both cover teams, sites, remote rules, traffic analysis, and request inspection. Agent guard policies are MCP-only, so an agent that has to author or publish a policy needs the MCP server. For the full surface, see the CLI command reference and the MCP tool list.
If the user doesn’t have an Arcjet account, direct them to console.arcjet.com to create one or register on their behalf using agent registration. Both transports authenticate as that user, so don’t prompt them for a token or an API key.
Path A: Connect with the CLI
Section titled “Path A: Connect with the CLI”The Arcjet CLI manages sites, keys, and rules from the terminal:
npx -y @arcjet/cli@latest auth loginnpx -y @arcjet/cli@latest teams listnpx -y @arcjet/cli@latest sites list --team-id team_01abc123npx -y @arcjet/cli@latest sites get-key --site-id site_01abc123auth login uses a browser-based device flow. For frequent use, install the
binary so you can run arcjet <command> directly. See
CLI install paths.
Path B: Connect with the MCP server
Section titled “Path B: Connect with the MCP server”The Arcjet MCP server manages your account from an AI coding tool. For the per-client configuration steps, see MCP server setup.
Authentication uses OAuth on first connection. Claude Code and ChatGPT open a browser automatically. Cursor, Codex CLI, and VS Code prompt you to authenticate first, so the user may have to click through before any tool call succeeds.
Once connected, retrieve the site key:
- Call
list-teamsto get available teams. - Call
list-siteswith the team ID to find the site, or callcreate-siteto create one. - Call
get-site-keywith the site ID to retrieve theARCJET_KEY.
Set the environment
Section titled “Set the environment”Whichever transport you used, set the key in the project environment:
# .env.local (Next.js, Astro) or .env (other frameworks)ARCJET_KEY=ajkey_yourkeyARCJET_ENV=developmentARCJET_ENV=development switches the SDK in the local app into development
mode, which allows the private and loopback IP addresses that are normal on a
developer machine. It’s read by the JavaScript and Python SDKs and ignored by
the Go SDK, which has no development mode. It has nothing to do with the CLI or
the MCP connection. For more information, see
Environment variables.
Install Arcjet
Section titled “Install Arcjet”Install the package for the framework you detected. Coding agents need no package at all.
Coding agents
Section titled “Coding agents”Enforce security policies on developer coding agents. There is no package to install, and no code changes. An administrator configures the hooks the agent already fires. See Claude Code, GitHub Copilot, OpenAI Codex, and Cursor.
AI agent frameworks
Section titled “AI agent frameworks”Protect custom-built agents with direct framework integrations. Each one uses
the guard SDK (@arcjet/guard or arcjet.guard) with the framework package as
a peer.
| Framework | Install command |
|---|---|
| Claude Agent SDK | npm i @arcjet/guard @anthropic-ai/claude-agent-sdk or pip install "arcjet[claude-agent-sdk]" |
| Claude Managed Agents | npm i @arcjet/guard @anthropic-ai/sdk or pip install "arcjet[claude-managed-agents]" |
| CrewAI | pip install "arcjet>=1.0.0" "crewai>=1.15.3,<2" |
| Genkit | npm i @arcjet/guard genkit |
| Google ADK | npm i @arcjet/guard @google/adk or pip install "arcjet[google-adk]" |
| Cloudflare Think | npm i @arcjet/guard @cloudflare/think |
| LangChain | npm i @arcjet/guard langchain @langchain/core or pip install "arcjet[langchain]" |
| LangGraph | npm i @arcjet/guard @langchain/langgraph @langchain/core |
| Mastra | npm i @arcjet/guard @mastra/core |
| OpenAI Agents | npm i @arcjet/guard @openai/agents or pip install "arcjet[openai-agents]" |
| Strands Agents | npm i @arcjet/guard @strands-agents/sdk or pip install "arcjet[strands-agents]" |
| TanStack AI | npm i @arcjet/guard @tanstack/ai |
| Vercel AI SDK | npm i @arcjet/guard ai @ai-sdk/provider-utils |
| Vercel Eve | npm i @arcjet/guard eve |
Where a row lists only an npm command, that adapter is JavaScript-only.
Cloudflare Think is JavaScript-only.
CrewAI is Python-only, and has no arcjet[crewai] extra, so install CrewAI
yourself. LangChain splits its extras: arcjet[langchain] covers guard_tool
and the capture handlers, and arcjet[langchain-agents] covers
ArcjetMiddleware and ToolPolicy. Claude Managed Agents needs the extra
steps in Claude Managed Agents. For every adapter,
see Guards.
Import paths are versioned. @arcjet/guard/vercel-ai/v7 resolves and
@arcjet/guard/vercel-ai does not, which is deliberate: an unversioned import
throws ERR_PACKAGE_PATH_NOT_EXPORTED rather than silently changing behavior
across a major version.
Native SDKs
Section titled “Native SDKs”Create custom integrations and protect your application code.
| Framework | Install command |
|---|---|
| Astro | npx astro add @arcjet/astro |
| Bun | bun add @arcjet/bun @arcjet/inspect |
| Bun + Hono | bun add @arcjet/bun @arcjet/inspect |
| Deno | deno add npm:@arcjet/deno npm:@arcjet/inspect |
| Fastify | npm i @arcjet/fastify |
| Go | go get github.com/arcjet/arcjet-go@latest |
| NestJS | npm i @arcjet/nest |
| Next.js | npm i @arcjet/next |
| Node.js | npm i @arcjet/node @arcjet/inspect |
| Node.js + Express | npm i @arcjet/node @arcjet/inspect |
| Node.js + Hono | npm i @arcjet/node @arcjet/inspect |
| Nuxt | npx nuxt module add @arcjet/nuxt |
| Python + FastAPI | pip install arcjet or uv add arcjet |
| Python + Flask | pip install arcjet or uv add arcjet |
| React Router | npm i @arcjet/react-router @arcjet/inspect |
| Remix | npm i @arcjet/remix @arcjet/inspect |
| SvelteKit | npm i @arcjet/sveltekit @arcjet/inspect |
Claude Managed Agents
Section titled “Claude Managed Agents”Claude Managed Agents is Anthropic’s hosted harness. It is not the Claude Agent
SDK, so don’t install claude-agent-sdk or @anthropic-ai/claude-agent-sdk
for this adapter.
For JavaScript, install the guard SDK with @anthropic-ai/sdk (>=0.86.0 <1):
npm i @arcjet/guard @anthropic-ai/sdkFor Python, install the extra, which brings anthropic>=0.92.0,<2:
pip install "arcjet[claude-managed-agents]"Or uv add the same spec. One adapter, both languages. Import
@arcjet/guard/claude-managed-agents/v0 (guardEvents, guardCustomTool,
claudeManagedAgentsContext) or arcjet.guard.claude_managed_agents
(guard_events, guard_custom_tool, claude_managed_agents_context).
This adapter has no protect() call. Screen inbound user.message with
guardEvents or guard_events before events.send, and wrap custom tools
with guardCustomTool or guard_custom_tool before your app executes them. On
a custom-tool DENY, return user.custom_tool_result with is_error set.
Anthropic runs built-in tools and the default is always_allow, so there’s no
pre-execution hook for bash or file tools. always_ask with
user.tool_confirmation is opt-in human confirmation, not policy. For MCP, put
Guard on servers you host. For more information, see
Claude Managed Agents agent guard.
Add protection
Section titled “Add protection”A typical setup has three steps:
- Create an Arcjet client once, outside request handlers.
- Configure rules.
- Call
protect()orguard()at the protection site, then act on the decision.
Protect an HTTP route
Section titled “Protect an HTTP route”Configure shield (WAF), detectBot, rate limiting (tokenBucket,
fixedWindow, or slidingWindow), and optionally sensitiveInfo or
detectPromptInjection for AI apps. Call protect() inside each route handler
and check whether the decision was denied.
In Go, log the err from Protect and deny only when IsDenied() is true. A
transport failure returns an ERROR decision that IsAllowed() treats as
allowed, so use IsErrored() to distinguish it from a real allow. If the
client or request is nil, Protect returns the zero Decision.
Guard an agent action
Section titled “Guard an agent action”A guard call needs no request object. Create the client once, configure rules, then evaluate them at the action boundary:
import { launchArcjet, detectPromptInjection, tokenBucket,} from "@arcjet/guard";
// Create the client once, at module scope.const arcjet = launchArcjet({ key: process.env.ARCJET_KEY! });
const promptScan = detectPromptInjection();const lookupLimit = tokenBucket({ refillRate: 10, intervalSeconds: 60, maxTokens: 10,});
export async function lookupOrder(userId: string, orderNumber: string) { const decision = await arcjet.guard({ label: "order.looked-up", rules: [ promptScan(orderNumber), lookupLimit({ key: userId, requested: 1 }), ], });
if (decision.conclusion === "DENY") { throw new Error(`Denied: ${decision.reason}`); }
return await db.orders.find(orderNumber);}The same call in Python, where guard() has a guard_sync() pair:
import os
from arcjet.guard import launch_arcjet, DetectPromptInjection
aj = launch_arcjet(key=os.environ["ARCJET_KEY"])prompt_scan = DetectPromptInjection()
decision = await aj.guard( label="order.looked-up", rules=[prompt_scan(order_number)],)
if decision.conclusion == "DENY": raise RuntimeError(f"Denied: {decision.reason}")Labels are slugs: lowercase letters, digits, dash, underscore, and dot. They
must start and end with a lowercase letter or digit. Uppercase is rejected, so
use tools.get-weather or tools.get_weather, not tools.getWeather.
Hardcode them rather than building them from user input, so they stay
greppable and the Console can group by them.
The JavaScript guard client is async and has no blocking variant. Python has a
_sync pair for every entry point (launch_arcjet_sync(), guard_sync()),
which is what a queue worker or other synchronous job needs. Go guard rule
constructors require Mode (ModeLive or ModeDryRun), and an empty Mode
returns ErrInvalidMode. HTTP Protect rules default an empty Mode to
ModeDryRun.
For complete, copy-paste examples for every framework, including the rule parameter reference and decision API, see llms-full.txt. llms.txt is a shorter index that links out to the full reference.
Recommended rules by app type
Section titled “Recommended rules by app type”| App type | Rules |
|---|---|
| AI or LLM chat | shield + detectBot + tokenBucket + sensitiveInfo + detectPromptInjection |
| Public API | shield + detectBot + fixedWindow or tokenBucket |
| Signup or login form | shield + detectBot + validateEmail + slidingWindow |
| Internal or admin route | shield + filter (country/VPN blocking) |
| Any web app | shield + detectBot (good baseline) |
| AI agent tool call (Guard) | tokenBucket + detectPromptInjection + localDetectSensitiveInfo |
| MCP tool handler (Guard) | tokenBucket (keyed by session) + detectPromptInjection |
| Queue worker or background job (Guard) | tokenBucket (keyed by user) + detectPromptInjection + localDetectSensitiveInfo |
| Claude Managed Agents (Guard) | tokenBucket + detectPromptInjection + localDetectSensitiveInfo on inbound user.message and custom tools |
localDetectSensitiveInfo detects EMAIL, PHONE_NUMBER, IP_ADDRESS, and
CREDIT_CARD_NUMBER with the bundled detector, entirely on-device. Names,
addresses, and government or financial identifiers need the Rampart backend.
Pass backend: rampart() on the rule, or sensitiveInfoBackend: rampart() on
the client to cover the sensitive information rule in a remote policy too.
Secure the coding agent
Section titled “Secure the coding agent”The hooks Claude Code, GitHub Copilot, OpenAI Codex, and Cursor already fire can call Arcjet before every tool call, with no SDK and no code change. An administrator installs one hook entry per event and publishes the policies to enforce. For the hook configuration and the starter policies, see Secure coding agents.
Configure an agent guard policy
Section titled “Configure an agent guard policy”A policy decides the action for a guard call, and it’s managed outside the application, so it changes without a deployment. Policies are MCP-only: the CLI has no policy commands.
A direct guard() call selects a policy with label. A framework adapter
takes action instead, for the same slug. Passing label to guardTool()
doesn’t compile.
- Call
list-guard-policiesto see the site’s policies and their labels. - Call
get-guard-policyfor the policy’s contract: its label, and every input with its kind and exposure. Write theguard()call from that contract. A policy does nothing until the application sends values under exactly the names it declares, and a mistyped name produces a policy that silently never fires. - To create one, call
describe-guard-policywith a Guard label and a description of what the action must refuse, thenvalidate-guard-policyto compile it and run its stored tests, thenput-guard-policyto publish.
A coding agent policy is selected by what it executes on rather than by a
label, and its inputs are fixed. Pass describe-guard-policy a draft that
already carries the contract and the execute-on setting, or copy a starter
policy from Coding agent policies.
A policy’s conditions are Rego over the declared inputs, and they can read Arcjet’s own detector findings as facts. A policy with a live expression rule needs at least one stored test before it can publish. A policy whose rules are all dry run can be saved without tests, and detector-backed rules are exempt. For more information, see Author and publish policies.
Every framework adapter takes actor and inputs, in both JavaScript and
Python, each as a value or a function resolved per call. Build each input with
policyInput, which makes the wire type and the exposure explicit:
inputs: { recipient: policyInput.server.string(recipient), allowed_recipients: policyInput.server.stringList(allowlist), body: policyInput.local.string(body),}server values are transmitted to Arcjet. local values stay in SDK memory
and only a SHA-256 digest is sent. Derive actor from an authenticated
server-side identity and never from user-controlled input, because a policy can
be conditioned on it. For what a resolver receives in each adapter, see
Send an actor and policy inputs.
Verify
Section titled “Verify”After adding protection and starting the app:
-
Exercise the protection site. Send a test request to a protected route, or for guards, invoke the protected tool or task. A small script that calls the function twice, once to allow and once to exceed a limit, is enough. For MCP servers, send a tool call with the MCP client or inspector.
-
Read the decision your code received. Every guard decision has an
id(prefixgdec_), aconclusion, and per-ruleresults. Log it. -
For request-based protection, list and inspect decisions from the terminal:
Terminal window arcjet requests list --site-id site_01abc123arcjet requests details --site-id site_01abc123 --request-id <request-id>arcjet requests explain --site-id site_01abc123 --request-id <request-id>arcjet analyze traffic --site-id site_01abc123The equivalent MCP tools are
list-requests,get-request-details,explain-decision, andanalyze-traffic. -
For guard decisions, check the Arcjet Console. The CLI and MCP request commands cover request-based protection only, so there is no terminal equivalent for guards.
If decisions aren’t appearing, verify that ARCJET_KEY is set and that
protect() or guard() is actually being called. On JavaScript and Python,
check ARCJET_ENV too. For Claude Managed Agents, confirm guardEvents or
guard_events ran before events.send, and that guardCustomTool or
guard_custom_tool ran before each custom tool.
Common agent prompts
Section titled “Common agent prompts”These prompts work well when given to an AI coding agent with skills installed and either the CLI or the MCP server connected:
- “Set up Arcjet security for my app” adds shield, bot detection, and rate limiting end to end.
- “Protect my API routes with Arcjet” adds shield, bot detection, and rate limiting to all API routes.
- “Add prompt injection detection to my AI chat endpoint” adds
detectPromptInjectionwith message scanning. - “Block sensitive data from reaching my LLM” adds
sensitiveInfoin JavaScript, ordetect_sensitive_infoin Python, to scan for personal information. - “Rate limit my AI agent tool calls per user” wires up
tokenBucketkeyed by user inside each tool handler. - “Secure my MCP server” adds per-tool
guard()calls with hardcoded labels and session-scoped rate limits. - “Protect my queue worker from prompt injection” uses the Python
synchronous guard client (
launch_arcjet_sync) with prompt injection detection on job payloads. - “Block personal information in agent tool outputs” uses
localDetectSensitiveInfoon tool results, so data in tool outputs doesn’t leak back into the model context. - “Only let this agent email approved recipients” declares
recipientandallowed_recipientsinputs on anemail.sentpolicy and generates the Rego that denies anything else. - “Show me the policy behind this guard label” calls
get-guard-policyand writes theguard()call from the contract it returns. - “Give me a security briefing for my site” calls
get-security-briefingover MCP, orarcjet briefing --site-id <id>from the CLI. - “What would happen if I promote my dry-run rules to live?” calls
get-dry-run-impactto show blocked requests, affected IPs, and false-positive risk.
Reference
Section titled “Reference”- Quick start guide for framework-specific setup with full code examples
- Guards to protect tool calls, queues, and agentic pipelines without an HTTP request
- Claude Managed Agents agent guard for
inbound
user.messageand custom tools in Anthropic’s hosted harness - Arcjet CLI to manage sites, keys, and rules from the terminal
- MCP server for the full MCP tool reference and client setup
- Arcjet plugin, a bundled install that wires up MCP, skills, and coding rules together for Claude Code and Cursor users. It’s an alternative to the steps in this guide, not an additional step.
- llms.txt, a short machine-readable index for AI agents
- llms-full.txt, the full machine-readable reference with all framework examples, rule parameters, and the decision API
- Request remote rules to manage request rules from the Console or the MCP server without code changes
- Policy contract for labels, actors, typed inputs, detectors, and rules
- Write policies in Rego for the input document, the supported language subset, and what it excludes
- Policy examples for worked policies covering email, refunds, web fetch, databases, files, and budgets
- Observe agent activity to ingest agent activity with no code change
- Best practices for recommended patterns and anti-patterns