arcjet
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseArcjet
Arcjet
Contents
目录
Add Arcjet Protection to Your App
为你的应用添加Arcjet防护
Checklist
检查清单
- Step 1: Verify language support (JS/TS, Python, or Go only — stop if unsupported)
- Step 2: Connect to Arcjet platform (CLI → MCP → manual Console setup)
- Step 3: Detect protection type and read the appropriate reference file
- Step 4: Implement protection (separate client file, correct SDK, correct patterns)
- Step 5: Verify decisions are firing correctly (trigger a real call, then check CLI / MCP / Console)
- 步骤1:验证语言支持(仅支持JS/TS、Python或Go——若不支持则停止操作)
- 步骤2:连接到Arcjet平台(CLI → MCP → 手动控制台设置)
- 步骤3:检测防护类型并阅读对应的参考文档
- 步骤4:实现防护(独立客户端文件、正确的SDK、正确的模式)
- 步骤5:验证决策是否正确触发(发起真实调用,然后检查CLI / MCP / 控制台)
Step 1: Check Language Support
步骤1:检查语言支持
If the project's server-side code is not JavaScript, TypeScript, Python, or Go → tell the user in chat that Arcjet doesn't support their language yet. Don't modify the project, don't write a , don't invent a package. Just say it and stop.
NOTES.md如果项目的服务端代码不是JavaScript、TypeScript、Python或Go → 在聊天中告知用户Arcjet目前不支持他们的语言。不要修改项目、不要编写、不要自行创建包。只需告知用户并停止操作。
NOTES.mdStep 2: Get an ARCJET_KEY into the project's env file
步骤2:将ARCJET_KEY添加到项目的环境文件中
Before writing any code, the project needs a real in its env file. Don't write Arcjet code first and "leave the key as a TODO" — that just produces dead code. Get the key first, then wire it up.
ARCJET_KEYIn order of preference:
- Arcjet CLI (preferred). Check whether you're already signed in, then retrieve a key.
- Arcjet MCP server (endpoint: ) — for clients with built-in MCP. See references/mcp.md.
https://api.arcjet.com/mcp - Manual (last resort): tell the user to grab a key from https://app.arcjet.com.
在编写任何代码之前,项目的环境文件中需要一个真实的。不要先编写Arcjet代码然后“将密钥留作TODO”——这只会产生无效代码。先获取密钥,再进行配置。
ARCJET_KEY优先顺序:
- Arcjet CLI(首选)。检查是否已登录,然后获取密钥。
- Arcjet MCP服务器(端点:)——适用于内置MCP的客户端。请参阅references/mcp.md。
https://api.arcjet.com/mcp - 手动方式(最后手段):告知用户从https://app.arcjet.com获取密钥。
CLI bootstrap (the normal path)
CLI引导(常规流程)
bash
npx -y @arcjet/cli@latest auth status # is the user already signed in?bash
npx -y @arcjet/cli@latest auth status # 用户是否已登录?if not signed in:
若未登录:
npx -y @arcjet/cli@latest auth login # browser device flow, see references/cli.md
npx -y @arcjet/cli@latest teams list --output json --fields id,name
npx -y @arcjet/cli@latest sites list --team-id <team_id> --output json --fields id,name
npx -y @arcjet/cli@latest auth login # 浏览器设备流,请参阅references/cli.md
npx -y @arcjet/cli@latest teams list --output json --fields id,name
npx -y @arcjet/cli@latest sites list --team-id <team_id> --output json --fields id,name
if no suitable site exists:
若不存在合适的站点:
npx -y @arcjet/cli@latest sites create --team-id <team_id> --name "<project>"
npx -y @arcjet/cli@latest sites get-key --site-id <site_id> --output json --fields key
Write the `key` value to the project's env file as `ARCJET_KEY=ajkey_...`. Match whatever the project already does — filename, `.env.example` companion, `.gitignore` entry. If the project doesn't have a convention yet, default to whatever the framework expects and add the env file to `.gitignore`. Never hardcode the key in source.
See [references/cli.md](references/cli.md) for install options beyond `npx`, agent-mode flags, and the full command reference.npx -y @arcjet/cli@latest sites create --team-id <team_id> --name "<project>"
npx -y @arcjet/cli@latest sites get-key --site-id <site_id> --output json --fields key
将`key`值写入项目的环境文件,格式为`ARCJET_KEY=ajkey_...`。遵循项目已有的约定——文件名、`.env.example`配套文件、`.gitignore`中的条目。如果项目尚无约定,则默认采用框架期望的方式,并将环境文件添加到`.gitignore`中。绝对不要在源代码中硬编码密钥。
有关`npx`之外的安装选项、代理模式标志和完整命令参考,请参阅[references/cli.md](references/cli.md)。Install the SDK with the project's package manager
使用项目的包管理器安装SDK
Once you know which SDK you need (Step 3 below), install it via the package manager the project already uses — , , , , , , , , etc. Don't hand-edit / / and guess a version: typed versions tend to be wrong ( doesn't exist for the Python SDK; is stale for ; Go should use the module tag, not a copied pseudo-version), and the lockfile/module metadata won't get updated. Let the package manager pick the real version and pin it.
npm installpnpm addyarn addbun addpip installuv addpoetry addgo getpackage.jsonrequirements.txtgo.modarcjet>=1.0.0^1.0.0@arcjet/next一旦确定所需的SDK(如下文步骤3),使用项目已有的包管理器进行安装——、、、、、、、等。不要手动编辑 / / 并猜测版本:手动输入的版本往往不准确(Python SDK不存在;的已过时;Go应使用模块标签而非复制的伪版本),且锁文件/元数据不会更新。让包管理器选择真实版本并固定。
npm installpnpm addyarn addbun addpip installuv addpoetry addgo getpackage.jsonrequirements.txtgo.modarcjet>=1.0.0@arcjet/next^1.0.0Step 3: Detect Protection Type and Read Reference
步骤3:检测防护类型并阅读参考文档
Determine which protection type applies:
| Request-based | Guard | |
|---|---|---|
| When to use | Code has an HTTP request object (Express | No HTTP request (tool calls, MCP handlers, queue workers, background jobs, agent loops) |
| JS/TS SDK | | |
| Python SDK | | |
| Go SDK | | |
| Entry point | | |
A single project can use both — e.g. request-based on API routes and guard on agent tool calls.
Common misclassifications to watch for:
- MCP servers: the word "server" is misleading. MCP tools don't receive HTTP requests — they're invoked by an MCP client over stdio or SSE. Use Guard, not request-based.
- Background jobs / queue consumers: no HTTP request at the protection site. Use Guard.
- Server actions / RPC over HTTP (Next.js server actions, tRPC, etc.): there is an HTTP request underneath. Use request-based.
- Agent tool calls inside a request handler: if you want to limit per-user-per-route, request-based is fine. If you want per-tool budgets independent of any HTTP boundary, use Guard at the tool call site.
Read the appropriate reference:
- Request-based JS/TS: references/requests_javascript.md
- Request-based Python: references/requests_python.md
- Request-based Go: references/requests_go.md
- Guard JS/TS: references/guards_javascript.md
- Guard Python: references/guards_python.md
- Guard Go: references/guards_go.md
These references explain architectural decisions and patterns that can't be inferred from the source code alone. For exact API signatures, read the installed package's types and doc comments.
确定适用的防护类型:
| 基于请求的防护 | Guard防护 | |
|---|---|---|
| 适用场景 | 代码包含HTTP请求对象(Express | 无HTTP请求(工具调用、MCP处理器、队列工作器、后台任务、Agent循环) |
| JS/TS SDK | | |
| Python SDK | | |
| Go SDK | | |
| 入口方法 | | |
单个项目可以同时使用两种防护——例如,API路由使用基于请求的防护,Agent工具调用使用Guard防护。
需要注意的常见误分类:
- MCP服务器:“服务器”一词具有误导性。MCP工具不接收HTTP请求——它们由MCP客户端通过stdio或SSE调用。请使用Guard防护,而非基于请求的防护。
- 后台任务/队列消费者:防护位置无HTTP请求。请使用Guard防护。
- 服务器操作/基于HTTP的RPC(Next.js服务器操作、tRPC等):底层存在HTTP请求。请使用基于请求的防护。
- 请求处理器内的Agent工具调用:如果要按用户按路由限制,基于请求的防护即可。如果要实现独立于任何HTTP边界的按工具预算限制,请在工具调用位置使用Guard防护。
阅读对应的参考文档:
- 基于请求的JS/TS:references/requests_javascript.md
- 基于请求的Python:references/requests_python.md
- 基于请求的Go:references/requests_go.md
- Guard JS/TS:references/guards_javascript.md
- Guard Python:references/guards_python.md
- Guard Go:references/guards_go.md
这些参考文档说明了无法从源代码中推断的架构决策和模式。有关确切的API签名,请阅读已安装包的类型和文档注释。
Step 4: Implement Protection
步骤4:实现防护
Follow the patterns in the reference file from Step 3. Key principles:
遵循步骤3中参考文档的模式。核心原则:
Request-based (HTTP routes):
基于请求的防护(HTTP路由):
- Create shared clients outside handlers and include Shield as a base rule. Use the exact constructor and rule names from the language reference.
- In JavaScript/TypeScript, use for route-specific rules and
withRule()for the result.decision.isDenied() - In Python, pass the complete rule list to /
arcjet(); there is noarcjet_sync()client method. Checkwith_rule().decision.is_denied() - In Go, create one at package scope.
NewClientderives route-specific clients and returnsWithRule(), so handle initialization errors. Check(*Client, error).decision.IsDenied() - Call /
protect()inside each route handler (not in app-level middleware), once per request.Protect() - Map denial reasons to HTTP responses. Only branch on reasons that produce a different response — there is no point in a Shield-specific arm that returns the same status as the default 403.
- Put the language's characteristic selector on the specific rule that needs it, then pass a trusted, authenticated user ID at protection time. Never rate limit by a client-controlled header unless a trusted proxy strips and rewrites it.
userId
- 在处理器外部创建共享客户端,并将Shield作为基础规则。使用语言参考中确切的构造函数和规则名称。
- 在JavaScript/TypeScript中,使用添加路由特定规则,并使用
withRule()判断结果。decision.isDenied() - 在Python中,将完整的规则列表传递给/
arcjet();不存在arcjet_sync()客户端方法。请检查with_rule()。decision.is_denied() - 在Go中,在包级别创建一个。
NewClient派生路由特定客户端并返回WithRule(),因此需要处理初始化错误。请检查(*Client, error)。decision.IsDenied() - 在每个路由处理器内部调用/
protect()(不要在应用级中间件中调用),每个请求调用一次。Protect() - 将拒绝原因映射到HTTP响应。仅对会产生不同响应的原因进行分支处理——如果Shield特定分支返回的状态码与默认403相同,则没有意义。
- 将语言的特征选择器添加到需要它的特定规则中,然后在防护时传递可信的、已认证的用户ID。除非可信代理会剥离并重写客户端控制的标头,否则绝不要按此类标头进行速率限制。
userId
Guard (non-HTTP code):
Guard防护(非HTTP代码):
- Client at module scope with (JS) or
launchArcjet()/launch_arcjet()(Python — pick async vs sync to match the function you're protecting).launch_arcjet_sync() - In Go, create one at package scope.
NewGuardClient - Rules declared at module scope. Give each rule a meaningful so they show up usefully in the Console.
label - One call per specific operation, with a hardcoded
guard()likelabelor"tools.get-weather". Put it wherever you already know exactly what's happening — that can be inside the tool/task function itself, or right before calling it from a dispatch arm. Both work; pick whichever makes error propagation cleaner. What to avoid is the generic-dispatcher pattern ("queue.summarize"callinghandleToolCall(name, args)) — interpolated labels break grep and produce messy Console groupings.guard(label=f"tools.{name}") - Label naming rules: labels are validated server-side as slugs — lowercase letters, digits, dash (), and dot (
-) only, must start and end with a letter or digit, max 256 bytes. Underscores, uppercase, and slashes are rejected even though some SDK TSDoc comments claim otherwise. Use., nottools.get-weatherortools.get_weather.Tools.GetWeather - Pass on the
metadatacall when you have useful auditing context (guard()). It appears in the Console alongside the decision.metadata={"user_id": user_id, "request_id": ...} - Branch on which rule denied, not just on . Use the per-rule accessors (e.g.
DENYfor retry-after info) or the flat reason string (userLimit.deniedResult(decision)in JS,decision.reason === "PROMPT_INJECTION"in Python) so the error you surface to the caller tells them why — "rate limited, retry in 12s" vs "input flagged as prompt injection" — instead of a generic "blocked." Note: guard'sdecision.reason == "PROMPT_INJECTION"is a flat string literal, unlike the request-based SDK's tagged-helper API.decision.reason - Every rate-limit rule needs a and a
key:bucket- Per-user context (agent tool calls inside a logged-in session, queue jobs with a ): use the user/session id as the key.
user_id - No user context (stdio MCP server, single-tenant worker): use a stable identifier you control — instance id, deployment name, or a literal like . Just be explicit.
"default"
- Per-user context (agent tool calls inside a logged-in session, queue jobs with a
- Check (JS),
decision.conclusion === "DENY"(Python), ordecision.conclusion == "DENY"/decision.IsDenied()(Go) before proceeding.decision.Conclusion == arcjet.ConclusionDeny
- 在模块级别使用(JS)或
launchArcjet()/launch_arcjet()(Python——根据要防护的函数选择异步或同步版本)创建客户端。launch_arcjet_sync() - 在Go中,在包级别创建一个。
NewGuardClient - 在模块级别声明规则。为每个规则赋予有意义的,以便在控制台中清晰显示。
label - 每个特定操作调用一次,并使用硬编码的
guard(),例如label或"tools.get-weather"。将其放置在你确切知道操作内容的位置——可以在工具/任务函数内部,也可以在从调度分支调用它之前。两种方式都可行;选择错误传播更清晰的方式。要避免的是通用调度器模式("queue.summarize"调用handleToolCall(name, args))——插值标签会破坏grep功能,并在控制台中产生混乱的分组。guard(label=f"tools.{name}") - 标签命名规则:标签在服务器端会被验证为slug——仅允许小写字母、数字、连字符()和点号(
-),必须以字母或数字开头和结尾,最大长度为256字节。即使某些SDK的TSDoc注释声称允许,下划线、大写字母和斜杠也会被拒绝。请使用.,而非tools.get-weather或tools.get_weather。Tools.GetWeather - 在调用中传递
guard()(当你有有用的审计上下文时,例如metadata)。它会与决策一起显示在控制台中。metadata={"user_id": user_id, "request_id": ...} - 根据哪个规则被拒绝进行分支处理,而不仅仅是。使用每个规则的访问器(例如,
DENY获取重试信息)或扁平的原因字符串(JS中userLimit.deniedResult(decision),Python中decision.reason === "PROMPT_INJECTION"),以便向调用者显示错误的原因——例如“速率限制,12秒后重试” vs “输入被标记为提示注入”——而非通用的“已拦截”。注意:Guard的decision.reason == "PROMPT_INJECTION"是扁平的字符串字面量,与基于请求的SDK的标记辅助API不同。decision.reason - 每个速率限制规则都需要和
key:bucket- 按用户上下文(登录会话内的Agent工具调用、带有的队列任务):使用用户/会话ID作为key。
user_id - 无用户上下文(stdio MCP服务器、单租户工作器):使用你控制的稳定标识符——实例ID、部署名称或文字值如。请明确指定。
"default"
- 按用户上下文(登录会话内的Agent工具调用、带有
- 在继续操作前检查(JS)、
decision.conclusion === "DENY"(Python)或decision.conclusion == "DENY"/decision.IsDenied()(Go)。decision.Conclusion == arcjet.ConclusionDeny
Conventions outside the Arcjet flow
Arcjet流程之外的约定
For everything that isn't an Arcjet-specific decision — dev scripts, file/module layout, named-vs-default exports, comment style, env-file naming, type hints, error class patterns — match the project's existing conventions. If the project has no convention yet, default to modern best practice for the language. This skill is opinionated about where Arcjet goes and how its API is used; it shouldn't reach further than that.
对于所有非Arcjet特定的决策——开发脚本、文件/模块布局、命名导出vs默认导出、注释风格、环境文件命名、类型提示、错误类模式——请遵循项目已有的约定。如果项目尚无约定,则默认采用该语言的现代最佳实践。此技能对Arcjet的放置位置和其API的使用方式有明确要求;不应超出此范围。
Step 5: Verify Decisions
步骤5:验证决策
After wiring up protection, confirm it's actually firing. Three steps:
1. Type-check / build first. Run , , , or whatever check command the project uses. Catches wrong imports, wrong rule names, and stale type signatures before the user does.
tscnext buildpython -m py_compile2. Trigger a real call so a decision exists to check. Without one, the Console and CLI are empty and you can't tell whether protection is actually wired up.
- Request-based: start the dev server (,
npm run dev, etc.) anduvicorn main:app --reloadthe protected route. To trip a rate limit, loop the call:curl— you should see a mix of 200s and 429s once the limit is hit.for i in {1..50}; do curl -s -o /dev/null -w "%{http_code}\n" http://localhost:3000/api/your-route; done - Guard: invoke the protected function directly. A tiny script that imports the tool/task function and calls it twice (once to allow, once to exceed the limit) is usually the fastest path — e.g. or
node -e "import('./src/tools.js').then(m => m.getWeather('SF', 'user_123'))". For MCP servers, send a tool call via the MCP client / inspector. For queue workers, enqueue a real job. Don't try to test guard bypython -c "from worker import process_job; process_job({'user_id': 'user_123'})"ing anything — there's no HTTP surface.curl
3. Confirm the decision in the Arcjet platform.
- CLI: (request-based) or
npx -y @arcjet/cli@latest requests list --site-id <id>(Guard)... guards list --site-id <id> - MCP: /
list-requestslist-guards - Console: https://app.arcjet.com
For deeper investigation: or .
arcjet requests explain --site-id <id> --request-id <id>arcjet guards explain --site-id <id> --guard-id <id>If you can't run the app in the current environment, tell the user exactly what to do (which command to run, what to look for in the output) instead of silently skipping verification.
配置好防护后,确认它实际触发。分为三个步骤:
1. 先进行类型检查/构建。运行、、或项目使用的任何检查命令。在用户发现之前捕获错误的导入、错误的规则名称和过时的类型签名。
tscnext buildpython -m py_compile2. 发起真实调用以生成可检查的决策。没有决策的话,控制台和CLI为空,无法判断防护是否已正确配置。
- 基于请求的防护:启动开发服务器(、
npm run dev等),并使用uvicorn main:app --reload调用受保护的路由。要触发速率限制,循环调用:curl——当达到限制时,你应该会看到200和429状态码混合出现。for i in {1..50}; do curl -s -o /dev/null -w "%{http_code}\n" http://localhost:3000/api/your-route; done - Guard防护:直接调用受保护的函数。一个导入工具/任务函数并调用两次(一次允许,一次超出限制)的小脚本通常是最快的方式——例如或
node -e "import('./src/tools.js').then(m => m.getWeather('SF', 'user_123'))"。对于MCP服务器,通过MCP客户端/检查器发送工具调用。对于队列工作器,入队一个真实任务。不要尝试通过python -c "from worker import process_job; process_job({'user_id': 'user_123'})"测试Guard防护——它没有HTTP接口。curl
3. 在Arcjet平台中确认决策。
- CLI:(基于请求的防护)或
npx -y @arcjet/cli@latest requests list --site-id <id>(Guard防护)... guards list --site-id <id> - MCP:/
list-requestslist-guards - 控制台:https://app.arcjet.com
如需深入调查:或。
arcjet requests explain --site-id <id> --request-id <id>arcjet guards explain --site-id <id> --guard-id <id>如果无法在当前环境中运行应用,请明确告知用户要执行的操作(运行哪个命令,在输出中查找什么内容),而非跳过验证。
Gotchas
常见陷阱
- Wrong SDK/client: ,
@arcjet/guard, and Go'sarcjet.guardare for non-HTTP code.NewGuardClient/@arcjet/node/ Python@arcjet/next/ Goarcjet()are for HTTP routes. Using the wrong one is the most common mistake.NewClient - Wrong placement: must not be called in Express middleware or Next.js middleware. Call it inside each route handler.
protect() - Wrong layer for : don't put
guard()in aguard()dispatcher — put it inside each specific tool / task function so thehandleToolCall(name, args)and metadata can be hardcoded.label - Hand-edited dependency manifests: don't append to
"arcjet": "^1.0.0"orpackage.jsontoarcjet>=1.0.0. Run the project's package manager so the version is real and the lockfile updates.requirements.txt - Double-counting: Calling or
protect()multiple times for the same operation counts against rate limits multiple times.guard() - Never hardcode — always use environment variables.
ARCJET_KEY
- 错误的SDK/客户端:、
@arcjet/guard和Go的arcjet.guard用于非HTTP代码。NewGuardClient/@arcjet/node/ Python@arcjet/next/ Goarcjet()用于HTTP路由。使用错误的客户端是最常见的错误。NewClient - 错误的放置位置:不得在Express中间件或Next.js中间件中调用。请在每个路由处理器内部调用。
protect() - 错误的层级:不要在
guard()调度器中放置handleToolCall(name, args)——请将其放在每个特定的工具/任务函数内部,以便硬编码guard()和元数据。label - 手动编辑依赖清单:不要在中追加
package.json或在"arcjet": "^1.0.0"中追加requirements.txt。运行项目的包管理器以获取真实版本并更新锁文件。arcjet>=1.0.0 - 重复计数:对同一操作多次调用或
protect()会多次消耗速率限制额度。guard() - 绝不要硬编码——始终使用环境变量。
ARCJET_KEY
Choosing Protections
选择防护类型
When you need to pick which rules address the user's concern — bot abuse, rate limits, prompt injection, signup spam, PII, IP filtering, etc. — load references/choosing_protections.md. It maps common problems to Arcjet rules and explains the tradeoffs between strategies (e.g. token bucket vs sliding window). The mapping doesn't need to be in your context for the rest of the workflow.
当你需要选择哪些规则来解决用户的问题——机器人滥用、速率限制、提示注入、注册垃圾信息、PII、IP过滤等——请查看references/choosing_protections.md。它将常见问题映射到Arcjet规则,并解释不同策略之间的权衡(例如令牌桶vs滑动窗口)。此映射无需在后续工作流程中保留在你的上下文里。
Resources
资源
For exact API signatures, parameter names, and the full set of rules and helpers, read the installed SDK's source — types and docstrings are the source of truth:
- Python SDK: https://github.com/arcjet/arcjet-py — package (request protection) and
arcjetsubpackage (non-HTTP guard).arcjet.guard - JavaScript / TypeScript SDK: https://github.com/arcjet/arcjet-js — monorepo with framework-specific packages (,
@arcjet/next,@arcjet/node,@arcjet/fastify,@arcjet/sveltekit, etc.).@arcjet/guard - Go SDK: https://github.com/arcjet/arcjet-go — module with request and guard clients. The initial tagged release is
github.com/arcjet/arcjet-go.v0.1.0 - Docs: https://docs.arcjet.com — narrative guides, blueprints, and product reference.
- Console: https://app.arcjet.com — sites, keys, and decision history.
有关确切的API签名、参数名称以及完整的规则和助手列表,请阅读已安装SDK的源代码——类型和文档字符串是权威来源:
- Python SDK:https://github.com/arcjet/arcjet-py — 包(请求防护)和
arcjet子包(非HTTP Guard防护)。arcjet.guard - JavaScript / TypeScript SDK:https://github.com/arcjet/arcjet-js — 包含框架特定包的单体仓库(、
@arcjet/next、@arcjet/node、@arcjet/fastify、@arcjet/sveltekit等)。@arcjet/guard - Go SDK:https://github.com/arcjet/arcjet-go — 模块,包含请求和Guard客户端。初始标记版本为
github.com/arcjet/arcjet-go。v0.1.0 - 文档:https://docs.arcjet.com — 叙述性指南、蓝图和产品参考。
- 控制台:https://app.arcjet.com — 站点、密钥和决策历史。