diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b65fa3..715d995 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,30 @@ this project adheres to [Semantic Versioning](https://semver.org/). ### Changed +- Synced the vendored skill tree with + [arcjet/skills](https://github.com/arcjet/skills) `main` at + `b9606c28` (2026-09-17, + [arcjet/skills#68](https://github.com/arcjet/skills/pull/68)). Follow-up to + the #27 sync of `c7bc1bb` (skills#67). Files were fetched from GitHub at + that SHA, then this repo’s `dprint` formatter was applied. Skills#68 is + docs-only in skills (18 markdown files). It drops stale 1.12.0 caveats + now that `@arcjet/guard` **1.13.0** and PyPI `arcjet` **1.2.0** are out + (every listed JS adapter plus `actor` / `inputs` / `validateGuardLabel` + ship in 1.13.0; `validate_guard_label` and adapter `actor` / `inputs` + are in Python 1.2.0). Step 3 adds a coding-agent hooks path (Claude + Code / GitHub Copilot): no SDK and no `guard()` call — install HTTP + hooks from https://docs.arcjet.com/coding-agents, copy the templates, + and omit `?surface=` (a hard-coded `cli` mislabels most traffic). + Label pre-check teaching now names `validateGuardLabel` / + `validate_guard_label` / `ValidateGuardLabel`. JS adapter refs replace + loose “Node.js 22+” with the published engines range + `>=22.21.0 <23 || >=24.5.0`. The skill table marks the Guard entry + point as core `guard({ label })` so it is not read as the wrapper + `action` API. Import `policyInput` from `@arcjet/guard`, not an + adapter path. Canonical copy is `plugins/arcjet/skills/` (`skills/` is + the inbound symlink). Deprecated alias skill directories are + unchanged. `evals/` is not vendored. No extra remote-policy teaching + beyond that SHA. - Synced the vendored skill tree with [arcjet/skills](https://github.com/arcjet/skills) `main` at `c7bc1bb` (2026-09-17, diff --git a/plugins/arcjet/skills/arcjet/SKILL.md b/plugins/arcjet/skills/arcjet/SKILL.md index a78222c..65e6057 100644 --- a/plugins/arcjet/skills/arcjet/SKILL.md +++ b/plugins/arcjet/skills/arcjet/SKILL.md @@ -67,16 +67,18 @@ Once you know which SDK you need (see Step 3), install it with the package manag Determine which protection type applies: -| | **Request-based** | **Guard** | -| --------------- | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | -| **When to use** | Code has an HTTP request object (Express `req`, Next.js `Request`, FastAPI `Request`) | No HTTP request (tool calls, MCP handlers, queue workers, background jobs, agent loops) | -| **JS/TS SDK** | Framework adapters such as `@arcjet/next`, `@arcjet/node`, `@arcjet/fastify` | `@arcjet/guard` | -| **Python SDK** | `arcjet` (with `arcjet()` / `arcjet_sync()`) | `arcjet` (with `launch_arcjet()` / `launch_arcjet_sync()`) | -| **Go SDK** | `github.com/arcjet/arcjet-go` (with `NewClient`) | `github.com/arcjet/arcjet-go` (with `NewGuardClient`) | -| **Entry point** | `protect(request)` / `Protect(ctx, r)` | `guard(label, rules)` / `Guard(ctx, request)` | +| | **Request-based** | **Guard** | +| --------------- | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | +| **When to use** | Code has an HTTP request object (Express `req`, Next.js `Request`, FastAPI `Request`) | No HTTP request (tool calls, MCP handlers, queue workers, background jobs, agent loops) | +| **JS/TS SDK** | Framework adapters such as `@arcjet/next`, `@arcjet/node`, `@arcjet/fastify` | `@arcjet/guard` | +| **Python SDK** | `arcjet` (with `arcjet()` / `arcjet_sync()`) | `arcjet` (with `launch_arcjet()` / `launch_arcjet_sync()`) | +| **Go SDK** | `github.com/arcjet/arcjet-go` (with `NewClient`) | `github.com/arcjet/arcjet-go` (with `NewGuardClient`) | +| **Entry point** | `protect(request)` / `Protect(ctx, r)` | Core JS `guard({ label, rules })`; Python `guard(label, …)`; Go `Guard(ctx, request)`. Wrappers take `action`, not `label`. | A single project can use both – for example, request-based on API routes and Guard on agent tool calls. If the project already uses a supported agent framework, prefer the official wrapper over hand-wrapping every tool. In Python, load the dedicated skill (table below) — not a raw `guard()` around every callable, and not the JS `@arcjet/guard/...` path. In JavaScript, load fundamentals plus **exactly one** adapter file from the JS table — not the sibling adapters. In Go, load the Microsoft Agent Framework skill when that framework is present; otherwise use `GuardAction` from the Go Guard reference. +**Coding-agent hooks (Claude Code / GitHub Copilot) are a third path.** There is no SDK and no `guard()` call. Publishing a policy attached to **Execute on** (Tool call or Prompt) turns it on. Install the HTTP hooks from https://docs.arcjet.com/coding-agents — copy the templates, do not invent URLs. Hook URLs must not name a policy and must omit `?surface=` (managed settings reach CLI, IDE, Desktop, and cloud; a hard-coded `cli` mislabels most traffic). Author the policy via MCP ([references/mcp.md](references/mcp.md)). + **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. @@ -141,9 +143,9 @@ Follow the patterns in the reference file from Step 3. Key principles: - **Branch on which rule denied**, not just `DENY`. Guard `decision.reason` is a flat string (`"PROMPT_INJECTION"`) and is `undefined` on ALLOW. A denial by one rule still spends the others' budget in the same `rules` array – split calls if a PII false positive must not drain a rate limit. - Every rate-limit rule needs a `key` and a `bucket`. Use a trusted user/session id when you have one; otherwise a stable identifier you control. -**JS adapters:** wrappers fail closed; core `guard()` fails open. Load the Step 3 file for the project's framework. Google ADK, TanStack AI, and Claude Managed Agents ship in `@arcjet/guard` **1.12.0** — `npm install @arcjet/guard` is enough. +**JS adapters:** wrappers fail closed; core `guard()` fails open. Load the Step 3 file for the project's framework. `npm install @arcjet/guard` is enough — every listed adapter, plus `actor` / `inputs` / `validateGuardLabel`, ships in **1.13.0**. -**Python:** `guard_action` / `guard_action_sync` is core. LangChain, CrewAI, and OpenAI Agents ship in PyPI `arcjet` **1.0.0** (still available in 1.1.0). Claude Agent SDK, Claude Managed Agents, and Strands Agents need **1.1.0** (`arcjet[claude-agent-sdk]`, `arcjet[claude-managed-agents]`, `arcjet[strands-agents]`). There is no `arcjet[crewai]` extra. +**Python:** `guard_action` / `guard_action_sync` is core. Load the dedicated skill for the project's extra (`arcjet[langchain]`, `arcjet[langchain-agents]`, `arcjet[openai-agents]`, `arcjet[claude-agent-sdk]`, `arcjet[claude-managed-agents]`, `arcjet[strands-agents]`). There is no `arcjet[crewai]` extra. `validate_guard_label` and adapter `actor` / `inputs` are in PyPI `arcjet` **1.2.0**. **Traps that run without error and enforce nothing** (full write-up in the Guard references and https://docs.arcjet.com/llms.txt): @@ -151,7 +153,7 @@ Follow the patterns in the reference file from Step 3. Key principles: - Python `LocalDetectSensitiveInfo()` with neither `allow` nor `deny` fail-opens as ALLOW (`AJ1203`). Always pass a list. JS works with no args; still pass a list. - The sensitive-info rule does **not** inherit the client's backend. Entity types beyond `EMAIL` / `PHONE_NUMBER` / `IP_ADDRESS` / `CREDIT_CARD_NUMBER` need `backend` on the rule. Share one Rampart instance with the client. - A label the service will not match reads as `ALLOW` with `hasFailedOpen()` / `has_failed_open()` false, so the guard silently does not run. `@arcjet/guard` 1.13.0 and PyPI `arcjet` 1.2.0 refuse one up front: adapter factories throw / raise `ArcjetInvalidLabelError`, and a capture warns `AJ1023` and still sends. Check a label you build yourself with `validateGuardLabel` / `validate_guard_label`. -- A remote policy that declares `actor` or typed `inputs` only fires if this call sends them. Python adapters all take `actor` / `inputs` (`server_input` / `local_input`) from 1.1.0. JS: core `guard()` plus every wrapper, which take `policyInput.server` / `policyInput.local` from `@arcjet/guard` 1.13.0; on 1.12.0 only `vercel-ai/v7` did. Check installed types — do not pass fields a helper does not declare. +- A remote policy that declares `actor` or typed `inputs` only fires if this call sends them. Import `policyInput` from `@arcjet/guard` (not an adapter path). Python uses `server_input` / `local_input`. Check installed types — do not pass fields a helper does not declare. - A missing decision is not a denial. If the model asks a question or masks values itself, Guard never runs. Verify in Console/CLI. - Guarding one tool only helps if it is the only path. Claude Agent SDK needs `settingSources: []` / `setting_sources=[]` **and** `strictMcpConfig: true` / `strict_mcp_config=True`. - HITL (`needsApproval`, `human_input`, `can_use_tool`, `event.interrupt()`, `always_ask`) is not a policy gate. @@ -205,6 +207,6 @@ For exact API signatures, parameter names, and the full set of rules and helpers - **Python Guard integration skills**: [integrate-arcjet-guard-langchain-py](../integrate-arcjet-guard-langchain-py/SKILL.md), [integrate-arcjet-guard-crewai](../integrate-arcjet-guard-crewai/SKILL.md), [integrate-arcjet-guard-openai-agents-py](../integrate-arcjet-guard-openai-agents-py/SKILL.md), [integrate-arcjet-guard-claude-agent-sdk-py](../integrate-arcjet-guard-claude-agent-sdk-py/SKILL.md), [integrate-arcjet-guard-claude-managed-agents-py](../integrate-arcjet-guard-claude-managed-agents-py/SKILL.md), [integrate-arcjet-guard-strands-agents-py](../integrate-arcjet-guard-strands-agents-py/SKILL.md). - **JavaScript / TypeScript SDK**: https://github.com/arcjet/arcjet-js – monorepo with framework-specific packages (`@arcjet/next`, `@arcjet/node`, `@arcjet/fastify`, `@arcjet/sveltekit`, `@arcjet/guard`). JS Guard adapter files: [references/guards_js_vercel_ai.md](references/guards_js_vercel_ai.md) and siblings listed in Step 3. - **Go SDK**: https://github.com/arcjet/arcjet-go – `github.com/arcjet/arcjet-go` module with request and guard clients. `go get github.com/arcjet/arcjet-go` resolves **v1.0.0** (Go 1.25+). Microsoft Agent Framework helpers live in a separate module: `go get github.com/arcjet/arcjet-go/agentframework` resolves **v0.1.0** and needs Go 1.26+. -- **Guard policies**: author and publish via MCP (`list-guard-policies` / `describe-guard-policy` / `validate-guard-policy` / `put-guard-policy`). The CLI has no policy commands. Application policies select by `label` / `action`. Coding-agent policies attach by **Execute on** (Tool call or Prompt); publishing turns them on — the hook URL must not name a policy. +- **Guard policies**: author and publish via MCP (`list-guard-policies` / `describe-guard-policy` / `validate-guard-policy` / `put-guard-policy`). The CLI has no policy commands. Application policies select by `label` / `action`. Coding-agent policies attach by **Execute on** (Tool call or Prompt); publishing turns them on — the hook URL must not name a policy and must omit `?surface=`. Install templates: https://docs.arcjet.com/coding-agents. - **Docs**: https://docs.arcjet.com – narrative guides, blueprints, and product reference. - **Console**: https://console.arcjet.com – sites, keys, and decision history. diff --git a/plugins/arcjet/skills/arcjet/references/choosing_protections.md b/plugins/arcjet/skills/arcjet/references/choosing_protections.md index 61f7d7c..06e4d10 100644 --- a/plugins/arcjet/skills/arcjet/references/choosing_protections.md +++ b/plugins/arcjet/skills/arcjet/references/choosing_protections.md @@ -69,3 +69,7 @@ Credential stuffing, spam registrations, and disposable email abuse on signup/lo Block traffic by IP metadata – VPN, Tor, country, or specific IP ranges. **Rules:** `filter` (request-based only). Can also be configured as remote rules via CLI/MCP for immediate response to active attacks without redeployment. + +## Claude Code / Copilot (no application SDK) + +Protecting the developer's own coding agent is not `protect()` or `@arcjet/guard`. Publish a coding-agent policy attached to **Execute on** (Tool call or Prompt) via MCP, then install the HTTP hooks from https://docs.arcjet.com/coding-agents. Copy the templates: the hook URL must not name a policy and must omit `?surface=`. diff --git a/plugins/arcjet/skills/arcjet/references/guards_go.md b/plugins/arcjet/skills/arcjet/references/guards_go.md index 8f132eb..30412fb 100644 --- a/plugins/arcjet/skills/arcjet/references/guards_go.md +++ b/plugins/arcjet/skills/arcjet/references/guards_go.md @@ -88,7 +88,7 @@ if decision.IsDenied() { } ``` -Labels are validated as slugs: lowercase letters, digits, dash (`-`), dot (`.`), and underscore (`_`), starting and ending with a lowercase letter or digit. Uppercase is rejected, so use `tools.get-weather` or `tools.get_weather`, not `tools.getWeather`. +Labels are validated as slugs: lowercase letters, digits, dash (`-`), dot (`.`), and underscore (`_`), starting and ending with a lowercase letter or digit. Uppercase is rejected, so use `tools.get-weather` or `tools.get_weather`, not `tools.getWeather`. Prefer dash/dot in new labels. Check a label you build yourself with `ValidateGuardLabel`. A slug the service will not match reads as `ALLOW` with `HasFailedOpen()` false, so the guard does not run. `Capture` warns `AJ1023` and still sends. ## Rate limits and keys @@ -102,7 +102,7 @@ An empty `Bucket` defaults to `default-token-bucket`, `default-fixed-window`, or - `GuardPromptInjection` – use on untrusted text before it reaches a model or tool argument. The result may include optional `Billing` (`tokens`). - `GuardSensitiveInfo` – use to block PII entering or leaving the system; scanning happens locally. Default backend is WASM (email, phone, IP, card). For names, addresses, and government / financial identifiers, set `Backend` to a `rampart.New(...)` from `github.com/arcjet/arcjet-go/sensitiveinfo/rampart`. Create the backend once at startup. -- `GuardModerateContent` – Guard-only content moderation. Result is binary `Detected` plus optional `Billing` (`text_units`). `ExperimentalGuardModerateContent` remains a deprecated alias until 1.0. +- `GuardModerateContent` – Guard-only content moderation. Result is binary `Detected` plus optional `Billing` (`text_units`). `ExperimentalGuardModerateContent` is a deprecated alias. - `GuardCustom` – runs your local custom function and reports the result to Arcjet. Keep the function deterministic and side-effect free. Go has no registration / free `guard()` API. Pass the client. diff --git a/plugins/arcjet/skills/arcjet/references/guards_javascript.md b/plugins/arcjet/skills/arcjet/references/guards_javascript.md index 4c41b0d..0dd1ab4 100644 --- a/plugins/arcjet/skills/arcjet/references/guards_javascript.md +++ b/plugins/arcjet/skills/arcjet/references/guards_javascript.md @@ -132,7 +132,7 @@ async function handleToolCall(name: string, args: Record, userI The `label` must be a hardcoded string – `"tools.get-weather"`, not `` `tools.${name}` ``. Hardcoded labels stay greppable, and the Console groups by them; interpolation produces a sea of distinct-looking calls instead of one bucket per operation. -**Label naming rules:** labels are validated as slugs – **lowercase letters, digits, dash (`-`), dot (`.`), and underscore (`_`)**, must start and end with a lowercase letter or digit, max 256 bytes. Uppercase and forward slashes are rejected, which is what catches a camelCase MCP tool name: use `tools.get-weather` or `tools.get_weather`, not `tools.getWeather`. +**Label naming rules:** labels are validated as slugs – **lowercase letters, digits, dash (`-`), dot (`.`), and underscore (`_`)**, must start and end with a lowercase letter or digit, max 256 bytes. Uppercase and forward slashes are rejected, which is what catches a camelCase MCP tool name: use `tools.get-weather` or `tools.get_weather`, not `tools.getWeather`. Prefer dash/dot in new labels. Check a label you build yourself with `validateGuardLabel` — a slug the service will not match reads as `ALLOW` with `hasFailedOpen()` false. Pass `metadata` whenever you have useful auditing context. It is nested JSON, not a flat string map – `{ user: { id: userId }, requestId }` is valid. It shows up in the Console and does not affect the decision. Do not put secrets or PII in it. @@ -174,7 +174,7 @@ JavaScript `localDetectSensitiveInfo()` works with no arguments, but always pass These produce code that runs without error and enforces nothing. Full list: https://docs.arcjet.com/llms.txt. - Pass `allow` or `deny` on every local sensitive-info rule. Share `backend` with the client for non-default entity types. -- A remote policy that declares `actor` or typed `inputs` only fires if this call sends them (`policyInput.server` / `policyInput.local`). Core `guard()` accepts them, and so does every wrapper from **1.13.0**. On 1.12.0 only `vercel-ai/v7` was typed for them. Check installed types — do not pass fields a helper does not declare. +- A remote policy that declares `actor` or typed `inputs` only fires if this call sends them. Import `policyInput` from `@arcjet/guard` (not an adapter path) and pass `policyInput.server` / `policyInput.local` on core `guard()` and every wrapper. Check installed types — do not pass fields a helper does not declare. - On Genkit, OpenAI Agents, and Strands Agents, `guardTool` cannot infer `TInput` – annotate `rules: (input: { … }) => …`. - A missing decision is not a denial. Verify in Console/CLI. - Adapter-specific isolation / session / correlation traps live in that adapter file. Do not copy them from a sibling. @@ -279,20 +279,20 @@ Import the **versioned** path. Unversioned aliases (`@arcjet/guard/vercel-ai`, ` Load **fundamentals here, then exactly one adapter file**. Do not open sibling adapters. This table is the source of truth — `SKILL.md` links here instead of copying it. -| Adapter | Import | Load | -| -------------------------- | ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -| Vercel AI SDK v7 | `@arcjet/guard/vercel-ai/v7` | [guards_js_vercel_ai.md](guards_js_vercel_ai.md) — typed for `actor` / `inputs` from 1.12.0, a release before the other wrappers | -| Vercel Eve v0 | `@arcjet/guard/vercel-eve/v0` | [guards_js_vercel_eve.md](guards_js_vercel_eve.md) | -| Mastra v1 | `@arcjet/guard/mastra/v1` | [guards_js_mastra.md](guards_js_mastra.md) | -| LangChain `createAgent` v1 | `@arcjet/guard/langchain/v1` | [guards_js_langchain.md](guards_js_langchain.md) | -| LangGraph v1 | `@arcjet/guard/langgraph/v1` | [guards_js_langgraph.md](guards_js_langgraph.md) | -| OpenAI Agents v0 | `@arcjet/guard/openai-agents/v0` | [guards_js_openai_agents.md](guards_js_openai_agents.md) | -| Genkit v1 | `@arcjet/guard/genkit/v1` | [guards_js_genkit.md](guards_js_genkit.md) | -| Claude Agent SDK v0 | `@arcjet/guard/claude-agent-sdk/v0` | [guards_js_claude_agent_sdk.md](guards_js_claude_agent_sdk.md) | -| Strands Agents v1 | `@arcjet/guard/strands-agents/v1` | [guards_js_strands_agents.md](guards_js_strands_agents.md) | -| Google ADK v2 | `@arcjet/guard/google-adk/v2` | [guards_js_google_adk.md](guards_js_google_adk.md) — ships in npm 1.12.0 | -| TanStack AI v0 | `@arcjet/guard/tanstack-ai/v0` | [guards_js_tanstack_ai.md](guards_js_tanstack_ai.md) — ships in npm 1.12.0 | -| Claude Managed Agents v0 | `@arcjet/guard/claude-managed-agents/v0` | [guards_js_claude_managed_agents.md](guards_js_claude_managed_agents.md) — ships in npm 1.12.0 | +| Adapter | Import | Load | +| -------------------------- | ---------------------------------------- | ------------------------------------------------------------------------ | +| Vercel AI SDK v7 | `@arcjet/guard/vercel-ai/v7` | [guards_js_vercel_ai.md](guards_js_vercel_ai.md) | +| Vercel Eve v0 | `@arcjet/guard/vercel-eve/v0` | [guards_js_vercel_eve.md](guards_js_vercel_eve.md) | +| Mastra v1 | `@arcjet/guard/mastra/v1` | [guards_js_mastra.md](guards_js_mastra.md) | +| LangChain `createAgent` v1 | `@arcjet/guard/langchain/v1` | [guards_js_langchain.md](guards_js_langchain.md) | +| LangGraph v1 | `@arcjet/guard/langgraph/v1` | [guards_js_langgraph.md](guards_js_langgraph.md) | +| OpenAI Agents v0 | `@arcjet/guard/openai-agents/v0` | [guards_js_openai_agents.md](guards_js_openai_agents.md) | +| Genkit v1 | `@arcjet/guard/genkit/v1` | [guards_js_genkit.md](guards_js_genkit.md) | +| Claude Agent SDK v0 | `@arcjet/guard/claude-agent-sdk/v0` | [guards_js_claude_agent_sdk.md](guards_js_claude_agent_sdk.md) | +| Strands Agents v1 | `@arcjet/guard/strands-agents/v1` | [guards_js_strands_agents.md](guards_js_strands_agents.md) | +| Google ADK v2 | `@arcjet/guard/google-adk/v2` | [guards_js_google_adk.md](guards_js_google_adk.md) | +| TanStack AI v0 | `@arcjet/guard/tanstack-ai/v0` | [guards_js_tanstack_ai.md](guards_js_tanstack_ai.md) | +| Claude Managed Agents v0 | `@arcjet/guard/claude-managed-agents/v0` | [guards_js_claude_managed_agents.md](guards_js_claude_managed_agents.md) | Docs are the merged pages at https://docs.arcjet.com/guards//. Language-specific `*-js` / `*-py` URLs redirect there. The JS SDK also ships `integrate-arcjet-guard-*` skills under `node_modules/@arcjet/guard/skills/` — this repo does not duplicate those as separately triggered skills. diff --git a/plugins/arcjet/skills/arcjet/references/guards_js_claude_agent_sdk.md b/plugins/arcjet/skills/arcjet/references/guards_js_claude_agent_sdk.md index 1ee496d..928b1fc 100644 --- a/plugins/arcjet/skills/arcjet/references/guards_js_claude_agent_sdk.md +++ b/plugins/arcjet/skills/arcjet/references/guards_js_claude_agent_sdk.md @@ -14,7 +14,7 @@ Exports: `guardTool`, `guardHooks`, `claudeAgentContext`, plus the shared - **`options.sessionId` must be a UUID, and a session id can only be created once.** A non-UUID exits the CLI with `Invalid session ID. Must be a valid UUID.`; passing the same id to a second `query()` exits with `Session ID … is already in use.` Mint one UUID per conversation, then continue it with `options.resume` – which is also what keeps every turn on one Sequence, since `claudeAgentContext` reads the hook's `session_id` first. - Isolation needs `settingSources: []` **and** `strictMcpConfig: true`. Guarding one tool only helps if it is the only path. - `ClaudeAgentOptions.sessionId` is unique per run; the Guard `sessionId` passed to `guardTool` / `guardHooks` is a long-lived actor id. -- `canUseTool` is not a policy gate (skipped by `allowedTools`, allow rules, `bypassPermissions` / `acceptEdits`), and annotations / sandbox settings are not enforcement. Do not double-wrap with `vercel-ai/v7`. +- `canUseTool` is not a policy gate (skipped by `allowedTools`, allow rules, `bypassPermissions` / `acceptEdits`), and annotations / sandbox settings are not enforcement. Optional `actor` / `inputs` take `policyInput` from `@arcjet/guard`. Do not double-wrap with `vercel-ai/v7`. ```typescript import { randomUUID } from "node:crypto"; diff --git a/plugins/arcjet/skills/arcjet/references/guards_js_claude_managed_agents.md b/plugins/arcjet/skills/arcjet/references/guards_js_claude_managed_agents.md index 0292d56..7a31776 100644 --- a/plugins/arcjet/skills/arcjet/references/guards_js_claude_managed_agents.md +++ b/plugins/arcjet/skills/arcjet/references/guards_js_claude_managed_agents.md @@ -17,7 +17,7 @@ Three gotchas first: - **`guardCustomTool`** (hosted) runs Guard before `execute`. On `DENY` (or unevaluated Guard under the default `onGuardError: "deny"`) `execute` does not run and `send` is invoked with a real `user.custom_tool_result` (`custom_tool_use_id`, denial text on `content`, **`is_error: true`**). On ALLOW the caller posts the success `user.custom_tool_result`. A throw leaves the hosted session idle waiting for a result; omitting `is_error` looks like success. This is not Claude Agent SDK `structuredContent`. - **`guardEvents`** is permit-then-send. `send` is `(body) => client.beta.sessions.events.send(session.id, body)`. `@anthropic-ai/sdk` `>=0.86.0` takes the session id as the first positional argument on both `send` and `stream` (`stream(session.id)`); Python is `stream(session_id=...)`. There is no wrapper that returns `{ send }`. Events that are not `user.message` pass through without an inbound screen. Inbound `"allow"` is a legitimate `onGuardError` choice because failing closed stops the agent answering. `agent.tool_use` is observe-only — the built-in already ran. - **`claudeManagedAgentsContext`** reads a **caller-owned** `correlationId` only. It never mints. It never reads Anthropic `session.id` / `sesn_…` / `sevt_…` / `id` / `traceId`. Do not `randomUUID()` a correlation id the way Claude Agent SDK `options.sessionId` requires, and do not pass Anthropic's session id as correlation. -- Fail closed by default (`onGuardError: "deny"`). Node.js 22+. Use `guardCustomTool` / `guardEvents` / `claudeManagedAgentsContext` only — not `guardTool`, `guardHooks`, `guardInbound`, `createAgentContext`, or `aiToolsContext`. Do not also wrap with `@arcjet/guard/claude-agent-sdk/v0` or `@arcjet/guard/vercel-ai/v7`. Docs: https://docs.arcjet.com/guards/claude-managed-agents/. Worked example: [`examples/claude-managed-agent`](https://github.com/arcjet/examples/tree/main/examples/claude-managed-agent). +- Fail closed by default (`onGuardError: "deny"`). Node.js `>=22.21.0 <23 || >=24.5.0`. Optional `actor` / `inputs` take `policyInput` from `@arcjet/guard`. Use `guardCustomTool` / `guardEvents` / `claudeManagedAgentsContext` only — not `guardTool`, `guardHooks`, `guardInbound`, `createAgentContext`, or `aiToolsContext`. Do not also wrap with `@arcjet/guard/claude-agent-sdk/v0` or `@arcjet/guard/vercel-ai/v7`. Docs: https://docs.arcjet.com/guards/claude-managed-agents/. Worked example: [`examples/claude-managed-agent`](https://github.com/arcjet/examples/tree/main/examples/claude-managed-agent). ```typescript import Anthropic from "@anthropic-ai/sdk"; diff --git a/plugins/arcjet/skills/arcjet/references/guards_js_genkit.md b/plugins/arcjet/skills/arcjet/references/guards_js_genkit.md index 3d7c1e6..3c304f0 100644 --- a/plugins/arcjet/skills/arcjet/references/guards_js_genkit.md +++ b/plugins/arcjet/skills/arcjet/references/guards_js_genkit.md @@ -15,7 +15,7 @@ Three gotchas first: - **`guardTool`** wraps the `ToolAction` from `ai.defineTool` so the closed-over handler never runs on `DENY`. Return the shared `ArcjetDenialResult` as completed `toolResponse.output`. Do not throw. Do not call `interrupt()`. Do not throw `ToolInterruptError`. Wrap the returned `ToolAction` (the callable `generate()` invokes), not the inner handler — wrapping outside `action()` keeps a denial off `outputSchema` validation. `generate()` discards the action objects and re-resolves by name, so `guardTool` also replaces the registry entries. It throws if it cannot replace one (a frozen store would otherwise run the unguarded original with no signal). - **`guardMiddleware`** is a `generate({ use })` middleware whose `tool` hook denies by returning a completed `ToolResponsePart` without calling `next()`. Already-branded (`guardTool`) actions skip the middleware guard when they can be looked up. Pass a **plain object `{ name, instantiate }`** — a raw function becomes a _model_ hook only. Names get a random suffix so two instances do not collide (`normalizeMiddleware` keeps the first registration under a given name). Requires the `generateMiddleware` `tool` hook (Genkit >= 1.33). - **`genkitContext`** preference: `context.correlationId` → `sessionId` → `conversationId` → a caller-owned `flowId` / `runId`, then envelope copies. It never mints an id. It never reads `traceId`. It never treats `interrupt` / `resumed` as correlation. Do not call `createAgentContext` inside a generate / tool callback. Do not read `Session.sessionId` from a Session constructed without an id (that class mints a UUID). Put the same id on `generate({ context })` _and_ on `guardMiddleware({ sessionId })` — the tool hook from `toRunOptions` is only `{ metadata, resumed }` (no ALS context). -- Fail closed by default (`onGuardError: "deny"`). Optional peer `genkit` `>=1.0.0 <2`. Zod is theirs, not ours. Node.js 22+. Do not also wrap with `@arcjet/guard/vercel-ai/v7`. Use `guardTool` / `guardMiddleware` / `genkitContext` only — not `guardInbound`, `guardApproval`, `guardAction`, `createAgentContext`, or `aiToolsContext`. +- Fail closed by default (`onGuardError: "deny"`). Optional peer `genkit` `>=1.0.0 <2`. Zod is theirs, not ours. Node.js `>=22.21.0 <23 || >=24.5.0`. Optional `actor` / `inputs` take `policyInput` from `@arcjet/guard`. Do not also wrap with `@arcjet/guard/vercel-ai/v7`. Use `guardTool` / `guardMiddleware` / `genkitContext` only — not `guardInbound`, `guardApproval`, `guardAction`, `createAgentContext`, or `aiToolsContext`. ```typescript import { launchArcjet, detectPromptInjection, tokenBucket } from "@arcjet/guard"; diff --git a/plugins/arcjet/skills/arcjet/references/guards_js_google_adk.md b/plugins/arcjet/skills/arcjet/references/guards_js_google_adk.md index 9b44251..91a311c 100644 --- a/plugins/arcjet/skills/arcjet/references/guards_js_google_adk.md +++ b/plugins/arcjet/skills/arcjet/references/guards_js_google_adk.md @@ -14,7 +14,7 @@ Three gotchas first: - **`guardPlugin`** returns a `BasePlugin` for `new Runner({ plugins })`. `beforeToolCallback` evaluates Guard and, on `DENY` or unevaluated Guard under the default `onGuardError: "deny"`, returns `{ arcjetDenied: true, … }` so `runAsync` never runs. Fail closed: always return that deny dict on error — never `undefined` (that executes the tool) and never throw (PluginManager treats a throw as a plugin error, not skip). On ALLOW it returns `undefined`. Do not invent a `guardTool` wrap around `FunctionTool`. - **`googleAdkContext`** preference: caller-owned `correlationId` → `sessionId` → `conversationId`, then envelope copies. It never mints an id. It never reads `traceId`. It never reads `invocationId` (ADK always generates it). It never reads `toolContext.sessionId` / `session.id` (session auto-ids). Do not call `createAgentContext` inside a plugin / tool callback. Put the same id on `runner.runAsync({ sessionId })` _and_ on `guardPlugin({ sessionId })`. -- Fail closed by default (`onGuardError: "deny"`). Optional peer `@google/adk` `>=2 <3`. Node.js 22+. Use `guardPlugin` / `googleAdkContext` only — not `guardTool`, `guardInbound`, `guardApproval`, `guardMiddleware`, `guardHooks`, `createAgentContext`, or `aiToolsContext`. Docs: https://docs.arcjet.com/guards/google-adk/. +- Fail closed by default (`onGuardError: "deny"`). Optional peer `@google/adk` `>=2 <3`. Node.js `>=22.21.0 <23 || >=24.5.0`. Optional `actor` / `inputs` take `policyInput` from `@arcjet/guard`. Use `guardPlugin` / `googleAdkContext` only — not `guardTool`, `guardInbound`, `guardApproval`, `guardMiddleware`, `guardHooks`, `createAgentContext`, or `aiToolsContext`. Docs: https://docs.arcjet.com/guards/google-adk/. ```typescript import { launchArcjet, detectPromptInjection, tokenBucket } from "@arcjet/guard"; diff --git a/plugins/arcjet/skills/arcjet/references/guards_js_langchain.md b/plugins/arcjet/skills/arcjet/references/guards_js_langchain.md index 101e86d..1cdb0f7 100644 --- a/plugins/arcjet/skills/arcjet/references/guards_js_langchain.md +++ b/plugins/arcjet/skills/arcjet/references/guards_js_langchain.md @@ -4,7 +4,7 @@ Load [guards_javascript.md](guards_javascript.md) for the client, rules, labels, Docs: https://docs.arcjet.com/guards/langchain/ -Exports: `guardTool`, `guardMiddleware`, `langchainContext`. There is no unversioned `@arcjet/guard/langchain` alias. This is JS `createAgent` + `createMiddleware({ wrapToolCall })` from the `langchain` package. It is not LangGraph Graph API (`StateGraph` + `ToolNode` — `@arcjet/guard/langgraph/v1`, docs https://docs.arcjet.com/guards/langgraph/). It is not Python LangChain (`arcjet.guard.langchain`, docs https://docs.arcjet.com/guards/langchain/). Ships in `@arcjet/guard` 1.11.0+. Optional peers `langchain` `>=1.2.0 <2` and `@langchain/core` `>=1 <2`. No `@langchain/langgraph` peer. This wrapper takes `action` + SDK `rules`, and from 1.13.0 also optional `actor` / `inputs` (`policyInput`) — check installed types. +Exports: `guardTool`, `guardMiddleware`, `langchainContext`. There is no unversioned `@arcjet/guard/langchain` alias. This is JS `createAgent` + `createMiddleware({ wrapToolCall })` from the `langchain` package. It is not LangGraph Graph API (`StateGraph` + `ToolNode` — `@arcjet/guard/langgraph/v1`, docs https://docs.arcjet.com/guards/langgraph/). It is not Python LangChain (`arcjet.guard.langchain`, docs https://docs.arcjet.com/guards/langchain/). Ships in `@arcjet/guard` 1.11.0+. Optional peers `langchain` `>=1.2.0 <2` and `@langchain/core` `>=1 <2`. No `@langchain/langgraph` peer. This wrapper takes `action` + SDK `rules` and optional `actor` / `inputs` (`policyInput` from `@arcjet/guard`). Three gotchas first: @@ -15,7 +15,7 @@ Three gotchas first: - **`guardTool`** wraps a LangChain `tool()` / `StructuredTool` so `func` / `invoke` never runs on `DENY`. Denial is a plain `ArcjetDenialResult` — this helper does not throw and does not fabricate a `ToolMessage`. `createAgent`'s `baseHandler` wraps a non-ToolMessage in a success `ToolMessage`. Distinct from LangGraph Graph API, where `ToolNode` wraps the same plain object (`status: "success"`); do not fabricate `status: "error"` there, and do not use that adapter here. - **`guardMiddleware`** is `createMiddleware({ wrapToolCall })` for `createAgent({ middleware })`. A `wrapToolCall` short-circuit returns a real `ToolMessage` (`content` = JSON of the payload, default status) without calling the inner handler. A bare object from `wrapToolCall` is the reducer-crash case. Do not throw (that drops the fields) and do not set `status: "error"`. Already-branded (`guardTool`) tools skip the middleware guard so Guard is not called twice. - **`langchainContext`** preference: `configurable.thread_id` (what `wrapToolCall` sees on `runtime.configurable` as of langchain 1.2.34), then caller-owned `sessionId` / `conversationId`. It never mints an id. It never reads `traceId`. A resumed run keeps its `thread_id` because `humanInTheLoopMiddleware` resumes with `agent.invoke(new Command({ resume }), config)` — same config, same Sequence. The interrupt and its resume value are not correlation sources; do not derive an id from that payload. Do not call `createAgentContext` inside a `createAgent` callback. -- Fail closed by default (`onGuardError: "deny"`). Node.js 22+. Do not also wrap with `@arcjet/guard/vercel-ai/v7`. Use `guardTool` / `guardMiddleware` / `langchainContext` only — not `guardInbound`, `guardApproval`, `guardToolNode`, `guardHooks`, `createAgentContext`, or `aiToolsContext`. Docs: https://docs.arcjet.com/guards/langchain/. +- Fail closed by default (`onGuardError: "deny"`). Node.js `>=22.21.0 <23 || >=24.5.0`. Do not also wrap with `@arcjet/guard/vercel-ai/v7`. Use `guardTool` / `guardMiddleware` / `langchainContext` only — not `guardInbound`, `guardApproval`, `guardToolNode`, `guardHooks`, `createAgentContext`, or `aiToolsContext`. Docs: https://docs.arcjet.com/guards/langchain/. ```typescript import { launchArcjet, detectPromptInjection, tokenBucket } from "@arcjet/guard"; diff --git a/plugins/arcjet/skills/arcjet/references/guards_js_langgraph.md b/plugins/arcjet/skills/arcjet/references/guards_js_langgraph.md index 68dac09..39aecb9 100644 --- a/plugins/arcjet/skills/arcjet/references/guards_js_langgraph.md +++ b/plugins/arcjet/skills/arcjet/references/guards_js_langgraph.md @@ -10,7 +10,7 @@ Exports: `guardTool`, `guardToolNode`, `langgraphAgentContext`. There is no unve - **`guardToolNode`** guards the tools a `ToolNode` executes (MCP / runtime-discovered / unwrapped tools). It guards in place and returns the same node. A frozen tools array throws. The tools-array form returns copies and leaves the input array alone. Already-guarded tools are skipped so Guard is not called twice. - **`langgraphAgentContext`** reads `configurable.thread_id`, then the run id, then `configurable.checkpoint_ns`. It never mints an id. Do not call `createAgentContext` inside a LangGraph callback. - There is no `guardInbound` (screen before `graph.invoke` or in the first node). There is no `guardApproval` / `guardInterrupt`: `interrupt()` / `interrupt_before=["tools"]` is human HITL, not a policy gate (same trap as Mastra `requireApproval` and Claude `canUseTool`). -- Fail closed by default (`onGuardError: "deny"`). Do not also wrap with `@arcjet/guard/vercel-ai/v7`. +- Fail closed by default (`onGuardError: "deny"`). Optional peers `@langchain/langgraph` `>=1 <2` and `@langchain/core` `>=1 <2`. Node.js `>=22.21.0 <23 || >=24.5.0`. Optional `actor` / `inputs` take `policyInput` from `@arcjet/guard`. Do not also wrap with `@arcjet/guard/vercel-ai/v7`. ```typescript import { launchArcjet, tokenBucket } from "@arcjet/guard"; diff --git a/plugins/arcjet/skills/arcjet/references/guards_js_mastra.md b/plugins/arcjet/skills/arcjet/references/guards_js_mastra.md index 119dc1e..7eeace5 100644 --- a/plugins/arcjet/skills/arcjet/references/guards_js_mastra.md +++ b/plugins/arcjet/skills/arcjet/references/guards_js_mastra.md @@ -16,7 +16,7 @@ Three gotchas first: - **`guardProcessor`** for inbound / outbound text. On DENY, `processInput` / `processInputStep` call `abort()`; if `abort()` were to return, the processor still throws so the turn cannot fail open. Inbound `"allow"` is a legitimate `onGuardError` choice because failing closed stops the agent answering. - **`guardHooks`** — `beforeToolCall` returns `{ proceed: false, output }` on DENY so unwrapped MCP / workspace tools never execute. `afterToolCall` is observe-only. Pass `hooks` to the `Agent` constructor (or to `generate` / `stream`). - **`mastraAgentContext`** is exported from `@arcjet/guard/mastra/v1` in 1.11.0+. It reads `MASTRA_THREAD_ID_KEY`, then resource, then run. It never mints. It never calls `createAgentContext` (that splits the Sequence). Wrappers read `RequestContext` themselves; use this helper when calling core `guard()`. Set the reserved keys on `RequestContext` before `generate` / `stream`. -- Fail closed by default (`onGuardError: "deny"`). Optional peer `@mastra/core` `>=1 <2`. Node.js 22+. +- Fail closed by default (`onGuardError: "deny"`). Optional peer `@mastra/core` `>=1 <2`. Node.js `>=22.21.0 <23 || >=24.5.0`. Optional `actor` / `inputs` take `policyInput` from `@arcjet/guard`. ```typescript import { Agent } from "@mastra/core/agent"; diff --git a/plugins/arcjet/skills/arcjet/references/guards_js_openai_agents.md b/plugins/arcjet/skills/arcjet/references/guards_js_openai_agents.md index f58b3d0..012e67b 100644 --- a/plugins/arcjet/skills/arcjet/references/guards_js_openai_agents.md +++ b/plugins/arcjet/skills/arcjet/references/guards_js_openai_agents.md @@ -14,7 +14,7 @@ Three gotchas first: - **`guardTool`** wraps `FunctionTool.invoke` so the closed-over `execute` never runs on `DENY`. Return the shared `ArcjetDenialResult` (`{ arcjetDenied: true, … }`) on a `function_call_result` with `status: "completed"`. A throw hits `errorFunction` or `ToolCallError` and drops the fields. `timeoutMs` races the guard round trip as well as `execute`, so leave headroom; `outputGuardrails` / `customDataExtractor` receive the denial object and must not assume the tool's own shape. `guardTool` warns if `invoke` is handed neither a string nor an object (rules would silently see `{}`). - **`openaiAgentsContext`** preference: `context.correlationId` → `sessionId` → `conversationId` → `groupId`, then envelope copies (`conversationId`, `groupId`, already-resolved `sessionId`). It never mints an id. It never reads `traceId` (the SDK mints one when omitted). It never calls `session.getSessionId()` (`MemorySession` mints a UUID when constructed without `sessionId`). Do not call `createAgentContext` inside a run callback. -- Fail closed by default (`onGuardError: "deny"`). Optional peer `@openai/agents` `>=0.17.0 <1`. Zod is their peer, not ours. Node.js 22+. Do not also wrap with `@arcjet/guard/vercel-ai/v7`. +- Fail closed by default (`onGuardError: "deny"`). Optional peer `@openai/agents` `>=0.17.0 <1`. Zod is their peer, not ours. Node.js `>=22.21.0 <23 || >=24.5.0`. Optional `actor` / `inputs` take `policyInput` from `@arcjet/guard`. Do not also wrap with `@arcjet/guard/vercel-ai/v7`. ```typescript import { launchArcjet, detectPromptInjection, tokenBucket } from "@arcjet/guard"; diff --git a/plugins/arcjet/skills/arcjet/references/guards_js_strands_agents.md b/plugins/arcjet/skills/arcjet/references/guards_js_strands_agents.md index e3f8644..c1903d7 100644 --- a/plugins/arcjet/skills/arcjet/references/guards_js_strands_agents.md +++ b/plugins/arcjet/skills/arcjet/references/guards_js_strands_agents.md @@ -15,7 +15,7 @@ Three gotchas first: - **`guardTool`** wraps an authored `tool({ callback })` so the closed-over `_callback` (and ZodTool's `_functionTool._callback`) never runs on `DENY`. Denial is a plain `ArcjetDenialResult` — this helper does not throw and does not fabricate a `ToolResultBlock`. `FunctionTool` wraps the object in a `JsonBlock`. Prefer omitting `outputSchema` on guarded tools, or verify it accepts the denial shape. Register only the value this helper returns on `Agent({ tools })` — passing the original `tool()` alongside the wrap leaves the original `stream()` path unguarded. - **`guardHooks`** is a Plugin for `new Agent({ plugins })`. `initAgent` registers `BeforeToolCallEvent` (deny) and `AfterToolCallEvent` (capture only). A `BeforeToolCallEvent` deny sets `event.cancel` to `JSON.stringify` of `ArcjetDenialResult` so `tool.stream()` does not run; `AfterToolCallEvent` still fires. Already-branded (`guardTool`) tools skip the hook guard so Guard is not called twice. `cancel: true` uses a default message and loses the payload. - **`strandsAgentContext`** preference: caller-owned `invocationState.correlationId` → `sessionId` → `requestId`, then envelope copies, then `init.sessionId` / `init.correlationId`. It never mints an id. It never reads `traceId`. It never reads `agent.id`. It never calls `SessionManager`. Do not call `createAgentContext` inside an invoke / hook / tool callback. Put the same id on `invoke(..., { invocationState })` _and_ on `guardHooks({ sessionId })`. -- Fail closed by default (`onGuardError: "deny"`). Optional peer `@strands-agents/sdk` `>=1.1.0 <2`. Zod is theirs, not ours. Node.js 22+. Do not also wrap with `@arcjet/guard/vercel-ai/v7`. Use `guardTool` / `guardHooks` / `strandsAgentContext` only — not `guardInbound`, `guardApproval`, `guardMiddleware`, `guardToolNode`, `createAgentContext`, or `aiToolsContext`. Docs: https://docs.arcjet.com/guards/strands-agents/. +- Fail closed by default (`onGuardError: "deny"`). Optional peer `@strands-agents/sdk` `>=1.1.0 <2`. Zod is theirs, not ours. Node.js `>=22.21.0 <23 || >=24.5.0`. Optional `actor` / `inputs` take `policyInput` from `@arcjet/guard`. Do not also wrap with `@arcjet/guard/vercel-ai/v7`. Use `guardTool` / `guardHooks` / `strandsAgentContext` only — not `guardInbound`, `guardApproval`, `guardMiddleware`, `guardToolNode`, `createAgentContext`, or `aiToolsContext`. Docs: https://docs.arcjet.com/guards/strands-agents/. ```typescript import { launchArcjet, detectPromptInjection, tokenBucket } from "@arcjet/guard"; diff --git a/plugins/arcjet/skills/arcjet/references/guards_js_tanstack_ai.md b/plugins/arcjet/skills/arcjet/references/guards_js_tanstack_ai.md index 1cd9e4b..9f3b6a1 100644 --- a/plugins/arcjet/skills/arcjet/references/guards_js_tanstack_ai.md +++ b/plugins/arcjet/skills/arcjet/references/guards_js_tanstack_ai.md @@ -14,7 +14,7 @@ Three gotchas first: - **`guardMiddleware`** is `ChatMiddleware` for `chat({ middleware })`. Default DENY is an `onBeforeToolCall` skip with the shared `ArcjetDenialResult` without calling `execute`. Optional `onDeny: "abort"` stops the run on real DENY only (unavailable stays skip). Do not throw. Do not emit an interrupt to deny. - **`tanstackAiContext`** preference: caller-owned `context.correlationId` → `sessionId` → `conversationId`, then `init.sessionId` / `init.correlationId`. It never mints an id. It never reads `threadId`, `requestId`, `streamId`, or `traceId` (TanStack mints those). It never reads `runId`. A bare object that also has string `requestId` and `streamId` looks like TanStack's middleware envelope, so top-level `sessionId` on that object is ignored — pass `{ context: appContext }`. Do not call `createAgentContext` inside a `chat()` / middleware / tool callback. Put the same caller-owned id on `chat({ context })` _and_ on `guardMiddleware({ sessionId })`. -- Fail closed by default (`onGuardError: "deny"`). Optional peer `@tanstack/ai` `>=0.8.0 <1`. Zod is theirs, not ours. Node.js 22+. Do not also wrap with `@arcjet/guard/vercel-ai/v7`. Use `guardMiddleware` / `tanstackAiContext` only — not `guardTool`, `guardInbound`, `guardApproval`, `guardToolNode`, `guardHooks`, `createAgentContext`, or `aiToolsContext`. Docs: https://docs.arcjet.com/guards/tanstack-ai/. +- Fail closed by default (`onGuardError: "deny"`). Optional peer `@tanstack/ai` `>=0.8.0 <1`. Zod is theirs, not ours. Node.js `>=22.21.0 <23 || >=24.5.0`. Optional `actor` / `inputs` take `policyInput` from `@arcjet/guard`. Do not also wrap with `@arcjet/guard/vercel-ai/v7`. Use `guardMiddleware` / `tanstackAiContext` only — not `guardTool`, `guardInbound`, `guardApproval`, `guardToolNode`, `guardHooks`, `createAgentContext`, or `aiToolsContext`. Docs: https://docs.arcjet.com/guards/tanstack-ai/. ```typescript import { launchArcjet, detectPromptInjection, tokenBucket } from "@arcjet/guard"; diff --git a/plugins/arcjet/skills/arcjet/references/guards_js_vercel_ai.md b/plugins/arcjet/skills/arcjet/references/guards_js_vercel_ai.md index 94eea42..1e18937 100644 --- a/plugins/arcjet/skills/arcjet/references/guards_js_vercel_ai.md +++ b/plugins/arcjet/skills/arcjet/references/guards_js_vercel_ai.md @@ -4,7 +4,7 @@ Load [guards_javascript.md](guards_javascript.md) for the client, rules, labels, Docs: https://docs.arcjet.com/guards/vercel-ai/ -Exports: `guardTool`, `guardAction`, `captureAction`, `aiToolsContext`, `createAgentContext`, `securityMetadata`. There is no unversioned `@arcjet/guard/vercel-ai` alias. This is `ai` >= 7 `tool({ execute })` + `generateText` / `streamText` / `ToolLoopAgent`. Ships in `@arcjet/guard` 1.11.0+. Typed for `actor` / `inputs` (`policyInput.server` / `policyInput.local`) from 1.12.0, a release before the other wrappers, which take them from 1.13.0. Wrappers take `action`, not `label`. +Exports: `guardTool`, `guardAction`, `captureAction`, `aiToolsContext`, `createAgentContext`, `securityMetadata`. There is no unversioned `@arcjet/guard/vercel-ai` alias. This is `ai` >= 7 `tool({ execute })` + `generateText` / `streamText` / `ToolLoopAgent`. Wrappers take `action`, not `label`. Optional `actor` / `inputs` take `policyInput` imported from `@arcjet/guard`. Three gotchas first: @@ -16,7 +16,7 @@ Three gotchas first: - **`createAgentContext`** at the run entry. Pass a caller-owned `correlationId` when you have one (1–256 printable ASCII); omit to auto-generate a ULID. Thread the context by hand — never stash it in module state or ALS. - **`aiToolsContext(ctx, tools)`** maps that context onto `generateText` / `streamText`. Always add a system-prompt line that a denied tool must not be retried. - **`guardAction`** wraps an app-invoked function. Throws `ArcjetDeniedError` on DENY and `ArcjetGuardUnavailableError` when the policy could not be evaluated. `captureAction` is observe-only. -- Fail closed by default (`onGuardError: "deny"`). Optional peers `ai` >= 7 and `@ai-sdk/provider-utils`. Node.js 22+. Do not also wrap with Eve / Mastra / LangChain / Claude adapters. +- Fail closed by default (`onGuardError: "deny"`). Optional peers `ai` >= 7 and `@ai-sdk/provider-utils`. Node.js `>=22.21.0 <23 || >=24.5.0`. Do not also wrap with Eve / Mastra / LangChain / Claude adapters. ```typescript import { launchArcjet, detectPromptInjection, policyInput, tokenBucket } from "@arcjet/guard"; @@ -59,7 +59,6 @@ export async function runAgent(prompt: string) { action: "order.looked-up", actor: userId, rules: () => [lookupLimit({ key: userId, requested: 5 })], - // Only this adapter maps typed inputs to a remote policy. inputs: ({ orderId }) => ({ order_id: policyInput.server.string(orderId), }), diff --git a/plugins/arcjet/skills/arcjet/references/guards_python.md b/plugins/arcjet/skills/arcjet/references/guards_python.md index 71a3fac..ad4e121 100644 --- a/plugins/arcjet/skills/arcjet/references/guards_python.md +++ b/plugins/arcjet/skills/arcjet/references/guards_python.md @@ -125,7 +125,7 @@ async def handle_tool_call(name: str, args: dict, user_id: str): # 👎 The `label` must be a hardcoded string – `"tools.get-weather"`, not `f"tools.{name}"`. Hardcoded labels stay greppable, and the Console groups by them. -**Label naming rules:** labels are validated as slugs – **lowercase letters, digits, dash (`-`), dot (`.`), and underscore (`_`)**, must start and end with a lowercase letter or digit, max 256 bytes. Uppercase and forward slashes are rejected, which is what catches a camelCase MCP tool name: use `tools.get-weather` or `tools.get_weather`, not `tools.getWeather`. +**Label naming rules:** labels are validated as slugs – **lowercase letters, digits, dash (`-`), dot (`.`), and underscore (`_`)**, must start and end with a lowercase letter or digit, max 256 bytes. Uppercase and forward slashes are rejected, which is what catches a camelCase MCP tool name: use `tools.get-weather` or `tools.get_weather`, not `tools.getWeather`. Prefer dash/dot in new labels. Check a label you build yourself with `validate_guard_label` — a slug the service will not match reads as `ALLOW` with `has_failed_open()` false. Pass `metadata` whenever you have useful auditing context. It is nested JSON, not a flat string map – `{"user": {"id": user_id}, "request_id": ...}` is valid. It shows up in the Console and does not affect the decision. Do not put secrets or PII in it. diff --git a/plugins/arcjet/skills/arcjet/references/mcp.md b/plugins/arcjet/skills/arcjet/references/mcp.md index f328e07..75804bc 100644 --- a/plugins/arcjet/skills/arcjet/references/mcp.md +++ b/plugins/arcjet/skills/arcjet/references/mcp.md @@ -84,7 +84,7 @@ Once connected, the MCP server exposes tools for managing teams, sites, keys, re **Add protection without redeploying:** `create-rule` (bot/filter in DRY_RUN) → `get-dry-run-impact` → `promote-rule` -**Author a Guard policy:** `list-guard-policies` → `describe-guard-policy` → `validate-guard-policy` → `put-guard-policy`. Application policies select by `label` / wrapper `action`. Coding-agent policies attach by **Execute on** (Tool call or Prompt), not by label; publishing turns them on. +**Author a Guard policy:** `list-guard-policies` → `describe-guard-policy` → `validate-guard-policy` → `put-guard-policy`. Application policies select by `label` / wrapper `action`. Coding-agent policies attach by **Execute on** (Tool call or Prompt), not by label; publishing turns them on. Install Claude Code / Copilot HTTP hooks from https://docs.arcjet.com/coding-agents — copy the templates. The hook URL must not name a policy and must omit `?surface=` (managed settings reach CLI, IDE, Desktop, and cloud; a hard-coded `cli` mislabels most traffic). ## Security notes diff --git a/plugins/arcjet/skills/integrate-arcjet-guard-agent-framework-go/SKILL.md b/plugins/arcjet/skills/integrate-arcjet-guard-agent-framework-go/SKILL.md index d0edcbe..2916386 100644 --- a/plugins/arcjet/skills/integrate-arcjet-guard-agent-framework-go/SKILL.md +++ b/plugins/arcjet/skills/integrate-arcjet-guard-agent-framework-go/SKILL.md @@ -103,7 +103,11 @@ Ask only what you cannot infer from the code; suggest defaults. 1. **Labels are hardcoded.** `Action: "refund.issued"`, never `fmt.Sprintf`. In a `GuardTools` policy function, `switch t.Name()`. 2. **`Action`, not `Label`.** Wrappers take `Action`; the raw - `GuardRequest` takes `Label`. Same slug. + `GuardRequest` takes `Label`. Same slug. `ToolPolicy.Action` and + `InboundPolicy.Action` are validated when you build the helper, not on + the first call — a typo returns an error from `GuardTool` / + `GuardTools` / `GuardMiddleware` at startup. Check a slug you build + yourself with `arcjet.ValidateGuardLabel`. 3. **Denial is a result.** See above. 4. **Correlation is caller-owned.** Put it on the context, or store it on the session under `agentframework.CorrelationIDStateKey`. Never