Skip to main content
ClaudeWave
Skill682 estrellas del repoactualizado 3d ago

integrate-arcjet-guard-langchain

Integrate Arcjet security into a LangChain JS createAgent using @arcjet/guard — wrap tool() / StructuredTool, put guardMiddleware on createAgent({ middleware }) for MCP / unwrapped tools, and read configurable.thread_id for correlation. Use when asked to add Arcjet to langchain createAgent, rate limit its tools, screen inbound messages, or block prompt injection / PII. This is LangChain JS, not the Python page.

Instalar en Claude Code
Copiar
git clone --depth 1 https://github.com/arcjet/arcjet-js /tmp/integrate-arcjet-guard-langchain && cp -r /tmp/integrate-arcjet-guard-langchain/arcjet-guard/skills/integrate-arcjet-guard-langchain ~/.claude/skills/integrate-arcjet-guard-langchain
Después abre una sesión nueva de Claude Code; el skill carga automáticamente.

SKILL.md

# Integrate Arcjet Guard into a LangChain JS createAgent

`@arcjet/guard`'s LangChain v1 namespace wraps the agent's existing Arcjet
client. It never talks to the Arcjet API itself. Three surfaces, one
decision rule:

- **An authored tool** (`tool()` / `StructuredTool`) → `guardTool()`.
  DENY returns a plain `ArcjetDenialResult`. Do not throw. Do not
  fabricate a `ToolMessage`. `createAgent`'s `baseHandler` wraps a
  non-ToolMessage in a success `ToolMessage`.
- **MCP / unwrapped / runtime-discovered tools** → `guardMiddleware()`.
  A `createAgent({ middleware })` middleware whose `wrapToolCall` is
  the invoke()-wide gate. It denies by returning a **real**
  `ToolMessage` (`content` = JSON of the payload, `tool_call_id` =
  `request.toolCall.id`, `name` = `request.toolCall.name`) without
  calling `handler`. Already-branded tools are skipped when
  `request.tool` can be looked up. Do not set `status: "error"`. Do
  not throw (throws bubble and drop `arcjetDenied`).
- **Correlation** → `langchainContext()` reads
  `configurable.thread_id` (what wrapToolCall sees on
  `runtime.configurable` as of langchain 1.2.34), then caller-owned
  `sessionId` / `conversationId`. It never mints a new id. It never
  reads `traceId`. A run that pauses on `interrupt()` resumes through
  the same config, so it keeps its `thread_id` and its later decisions
  stay on the Sequence that started it — the interrupt and its resume
  value are simply not correlation sources of their own.

This namespace is LangChain JS **`createAgent` + `wrapToolCall`**. Not
LangGraph Graph API (`StateGraph` + `ToolNode`) — that is
`@arcjet/guard/langgraph/v1`. Not `vercel-ai/v7`. Server-side provider
tools and headless `.implement()` tools are out of scope. Do not also
wrap the same tool with `@arcjet/guard/langgraph/v1` or
`@arcjet/guard/vercel-ai/v7`.

Docs live at
[docs.arcjet.com/guards/langchain-js/](https://docs.arcjet.com/guards/langchain-js/).
Do **not** use `/guards/langchain/` — that is the live Python page.

## Screen inbound before `agent.invoke` — there is no inbound hook. SDK middleware that is not `wrapToolCall` is not Guard.

There is no first-class inbound channel, so there is no
`guardInbound`. Put prompt-injection (and other inbound rules) in the
application before `agent.invoke`. `wrapModelCall` / `beforeModel` /
`afterModel` intercept the model call, not user text. They are not
this policy gate.

## `humanInTheLoopMiddleware` / `interrupt` is HITL, not a policy gate.

`humanInTheLoopMiddleware` / `interrupt()` / approve-edit-reject-respond
is human-in-the-loop. Same trap as Mastra `requireApproval`, Claude
`canUseTool`, LangGraph `interrupt()`, Genkit `toolApproval`, and
OpenAI Agents `needsApproval`. There is no `guardApproval`. Policy
sits on `wrapToolCall` only — do not deny in `afterModel`. HITL
already lives there.

## Deny inside `tool()` (and `guardMiddleware`'s `wrapToolCall`). MCP and unwrapped tools skip an unwrapped handler.

The authored `tool()` handler is the deny point for tools you own.
MCP tools, runtime-discovered tools, and anything not wrapped with
`guardTool` skip that handler. `guardMiddleware` is the invoke()-wide
gate for those.

`guardMiddleware` **can deny**. LangChain's official auth example
returns a `ToolMessage` without calling `handler`. wrapToolCall's
return is **not** passed through `baseHandler`. A duck-typed object
without the real class fails `ToolMessage.isInstance` and crashes the
messages reducer. Do not throw. Do not set `status: "error"`.

## Questions to ask the human first

Ask only what you cannot infer from the code; suggest defaults.

1. Which tools are **risky** (external side effects, irreversible, spends
   money, sends messages)? Those get `guardTool`. MCP / runtime-discovered
   / tools you did not author get `guardMiddleware`.
2. What **limits**? (e.g. "10 lookups/min per order" → `tokenBucket`.)
3. Who is the **user** for metadata — an opaque user/tenant ID (never PII)?
   Default: none. Pass it via `metadata` on the policy. Put the
   conversation / session id you already have on
   `agent.invoke(..., { configurable: { thread_id } })`. That id is the
   correlation id, not the user. wrapToolCall only sees
   `runtime.configurable.thread_id` as of langchain 1.2.34.
4. Is an Arcjet outage unacceptable? Every helper defaults to
   `onGuardError: "deny"`. Ask explicitly about inbound screening before
   `agent.invoke`: failing closed there means the agent does not run for
   the duration of the outage, so `"allow"` is a routine and legitimate
   choice at that one call site.

## The six things readers get wrong

1. **There is no `guardInbound`.** Screen prompt injection before
   `agent.invoke`. `wrapModelCall` / `beforeModel` / `afterModel` are
   not Guard.
2. **`humanInTheLoopMiddleware` / `interrupt()` is not a policy gate.**
   It is HITL. Policy sits on `wrapToolCall` only. Do not deny in
   `afterModel`.
3. **The import path is versioned and there is no alias.**
   `@arcjet/guard/langchain/v1`. `@arcjet/guard/langchain` does not
   resolve. Docs are `/guards/langchain-js/`, not `/guards/langchain/`.
4. **Correlation is read, never minted.** Do not call `createAgentContext`
   inside a middleware / tool callback — that generates a second id and
   splits the Sequence. Put the id you already chose on
   `configurable.thread_id`. Do not read `traceId`. Resuming after an
   `interrupt()` reuses the same config and therefore the same
   `thread_id`, so decisions after the pause already correlate to the
   originating Sequence — do not derive an id from the interrupt or its
   resume value.
5. **Do not double-wrap with `@arcjet/guard/langgraph/v1` or
   `@arcjet/guard/vercel-ai/v7`.** `guardTool` throws if the tool
   already carries the Arcjet protection brand. `guardMiddleware`
   skips branded tools so Guard is not double-called.
6. **Two denial envelopes. Do not collapse them.** `guardTool` returns
   a plain `ArcjetDenialResult`. `guardMiddleware` `wr
integrate-arcjet-guard-agentsSkill

Integrate Arcjet security into a Vercel AI SDK (v7) application using @arcjet/guard — wrap agent tools with guard checks, enforce rules on risky app actions, and emit audit events joined by one correlation ID. Use when asked to add Arcjet to an AI SDK app, protect or rate limit agent tool calls, guard AI agent actions, or audit what an agent did.

integrate-arcjet-guard-claude-agent-sdkSkill

Integrate Arcjet security into a Claude Agent SDK agent using @arcjet/guard — wrap tool() handlers, screen inbound prompts with UserPromptSubmit, and deny unwrapped built-in/MCP tools with PreToolUse. Use when asked to add Arcjet to a Claude Agent SDK or Claude Code agent, rate limit its tools, screen inbound messages, or block prompt injection / PII.

integrate-arcjet-guard-eveSkill

Integrate Arcjet security into a Vercel Eve agent using @arcjet/guard — add guard gates to tools and connections, screen inbound messages, and record agent lifecycle events correlated to the session. Use when asked to add Arcjet to an Eve agent, rate limit its tools, guard connection access, or screen inbound messages.

integrate-arcjet-guard-genkitSkill

Integrate Arcjet security into a Genkit JS agent using @arcjet/guard — wrap ai.defineTool, put guardMiddleware on generate({ use }) for unwrapped / MCP / filesystem tools, and read a caller-owned id from generate({ context }). Use when asked to add Arcjet to genkit, rate limit its tools, screen inbound messages, or block prompt injection / PII.

integrate-arcjet-guard-langgraphSkill

Integrate Arcjet security into a LangGraph Graph API agent using @arcjet/guard — wrap tool() / StructuredTool, wrap ToolNode for unwrapped MCP tools, and read thread_id for correlation. Use when asked to add Arcjet to a LangGraph StateGraph / ToolNode agent, rate limit its tools, screen inbound messages, or block prompt injection / PII.

integrate-arcjet-guard-mastraSkill

Integrate Arcjet security into a Mastra agent using @arcjet/guard — wrap createTool execute, screen input/output with a Processor tripwire, and gate unwrapped MCP/workspace tools with hooks. Use when asked to add Arcjet to a Mastra agent, rate limit its tools, screen inbound messages, or block prompt injection / PII.

integrate-arcjet-guard-openai-agentsSkill

Integrate Arcjet security into an OpenAI Agents text Agent using @arcjet/guard — wrap tool({ execute }), screen inbound before run(), and read a caller-owned id from runContext.context. Use when asked to add Arcjet to @openai/agents, rate limit its tools, screen inbound messages, or block prompt injection / PII.

integrate-arcjet-guard-strands-agentsSkill

Integrate Arcjet security into a Strands Agents JS app using @arcjet/guard — wrap tool({ callback }), put guardHooks on Agent({ plugins }) for unwrapped / MCP / vended tools, and read a caller-owned id from invocationState. Use when asked to add Arcjet to strands-agents, rate limit its tools, screen inbound messages, or block prompt injection / PII.