superagent Documentation

Superagent protects your AI applications against prompt injections, data leaks, and harmful outputs. Embed safety directly into your app and prove...

6,582 stars TypeScript TypeScript 1 file Β· ~39,661 tokens #ai#anthropic#guardrails#llm#openai#prompt-injection#security
RAW Doc

README

docs

This is a Next.js application generated with
Create Fumadocs.

Security Notice

CVE-2025-55182: This project uses Next.js and React Server Components. To protect against CVE-2025-55182 (a critical remote code execution vulnerability in React Server Components), ensure you're using:

  • React: 19.0.1, 19.1.2, or 19.2.1 (or later)
  • Next.js: 15.0.5, 15.1.9, 15.2.6, 15.3.6, 15.4.8, 15.5.7 (or 16.0.7+ if not using fumadocs), or later

The current versions in this project have been updated to patched versions. For more information, see the Vercel security bulletin.

Run development server:

bash
npm run dev
# or
pnpm dev
# or
yarn dev

Open http://localhost:3000 with your browser to see the result.

Explore

In the project, you can see:

  • lib/source.ts: Code for content source adapter, loader() provides the interface to access your content.
  • lib/layout.shared.tsx: Shared options for layouts, optional but preferred to keep.
Route Description
app/(home) The route group for your landing page and other pages.
app/docs The documentation layout and pages.
app/api/search/route.ts The Route Handler for search.

Fumadocs MDX

A source.config.ts config file has been included, you can customise different options like frontmatter schema.

Read the Introduction for further details.

Learn More

To learn more about Next.js and Fumadocs, take a look at the following
resources:


Content/Docs/Legacy/Agent Frameworks/Langgraph


title: LangGraph

Overview

When building AI agents that can execute commands, access files, or interact with external systems, security is paramount. Superagent acts as a security layer that:

  • Validates user prompts before they reach your AI model
  • Guards tool executions to prevent harmful operations
  • Filters tool outputs to ensure safe content handling
  • Provides detailed security analysis with CWE codes and violation types

Prerequisites

Before starting, ensure you have:

  • Node.js v20.0 or higher
  • A Superagent account with API key (sign up here)
  • An OpenAI API key or other LLM provider credentials
  • Basic familiarity with LangGraph

TypeScript

Install dependencies

bash title="terminal"
npm install superagent-ai @langchain/langgraph @langchain/openai @langchain/core zod

Configure the guard and LangGraph state

ts title="config.ts"
import { createGuard } from "superagent-ai";
import { ChatOpenAI } from "@langchain/openai";
import { StateGraph, MessagesAnnotation, Annotation } from "@langchain/langgraph";
import { HumanMessage, AIMessage } from "@langchain/core/messages";

const guard = createGuard({
  apiKey: process.env.SUPERAGENT_API_KEY!,
});

const llm = new ChatOpenAI({
  model: "gpt-5",
  temperature: 0,
});

const State = Annotation.Root({
  ...MessagesAnnotation.spec,
  blocked: Annotation<boolean>({
    default: () => false,
  }),
});

Build a guarded workflow

ts title="workflow.ts"
async function guardInput(state: typeof State.State) {
  const lastMessage = state.messages[state.messages.length - 1];
  const { rejected, reasoning } = await guard(lastMessage.content as string);

  if (rejected) {
    return {
      blocked: true,
      messages: [new AIMessage(`Cannot process: ${reasoning}`)],
    };
  }

  return { blocked: false };
}

async function generate(state: typeof State.State) {
  if (state.blocked) return {};

  const response = await llm.invoke(state.messages);
  return { messages: [response] };
}

const workflow = new StateGraph(State)
  .addNode("guard", guardInput)
  .addNode("generate", generate)
  .addEdge("__start__", "guard")
  .addEdge("guard", "generate")
  .addEdge("generate", "__end__");

export const app = workflow.compile();

Add guarded tools

ts title="tools.ts"
import { DynamicStructuredTool } from "@langchain/core/tools";
import { ToolNode } from "@langchain/langgraph/prebuilt";
import { z } from "zod";

async function executeCommand(command: string) {
  // replace with the side-effect you want the tool to perform
  return `Executed: ${command}`;
}

const shellTool = new DynamicStructuredTool({
  name: "shell",
  description: "Execute shell command",
  schema: z.object({
    command: z.string(),
  }),
  func: async ({ command }) => {
    const { rejected, reasoning } = await guard(command);
    if (rejected) {
      return `Blocked: ${reasoning}`;
    }

    return executeCommand(command); // implement your runner
  },
});

const llmWithTools = llm.bindTools([shellTool]);
const toolNode = new ToolNode([shellTool]);

const shouldRouteToTools = (state: typeof State.State) => {
  const last = state.messages[state.messages.length - 1];
  return last instanceof AIMessage && last.tool_calls?.length ? "tools" : "__end__";
};

const toolWorkflow = new StateGraph(State)
  .addNode("guard", guardInput)
  .addNode("generate", async (state) => {
    if (state.blocked) return {};
    const response = await llmWithTools.invoke(state.messages);
    return { messages: [response] };
  })
  .addNode("tools", toolNode)
  .addEdge("__start__", "guard")
  .addEdge("guard", "generate")
  .addConditionalEdges("generate", shouldRouteToTools)
  .addEdge("tools", "generate");

export const agent = toolWorkflow.compile();

Use the agent

ts title="usage.ts"
async function chat(userInput: string) {
  const result = await app.invoke({
    messages: [new HumanMessage(userInput)],
  });

  return result.messages[result.messages.length - 1].content;
}

const agentResponse = await agent.invoke({
  messages: [new HumanMessage("List files in current directory")],
});

for await (const chunk of await agent.stream({
  messages: [new HumanMessage("What's in the README?")],
})) {
  console.log(chunk);
}

Python

Install dependencies

bash title="terminal"
uv add superagent-ai langgraph langchain-openai langchain-core

Configure the guard and state

python title="config.py"
import asyncio
import operator
from typing import Annotated, Sequence, TypedDict

from langchain_core.messages import BaseMessage, HumanMessage, AIMessage, ToolMessage
from langchain_openai import ChatOpenAI
from langgraph.graph import StateGraph, END
from superagent_ai import create_guard

guard = create_guard(
    api_base_url="https://app.superagent.sh/api/guard",
    api_key="sk-...",
)

llm = ChatOpenAI(model="gpt-5")

class State(TypedDict):
    messages: Annotated[Sequence[BaseMessage], operator.add]
    blocked: bool

Build a guarded workflow

python title="workflow.py"
async def guard_input(state: State):
    last_message = state["messages"][-1]
    result = await guard(last_message.content)

    if result.rejected:
        return {
            "blocked": True,
            "messages": [AIMessage(content=f"Cannot process: {result.reasoning}")],
        }

    return {"blocked": False}


async def generate(state: State):
    if state.get("blocked", False):
        return {}

    response = await llm.ainvoke(state["messages"])
    return {"messages": [response]}


workflow = StateGraph(State)
workflow.add_node("guard", guard_input)
workflow.add_node("generate", generate)
workflow.set_entry_point("guard")
workflow.add_edge("guard", "generate")
workflow.add_edge("generate", END)

app = workflow.compile()

Add guarded tools

python title="tools.py"
from langchain_core.tools import tool


@tool
async def shell(command: str) -> str:
    """Execute shell command"""
    result = await guard(command)

    if result.rejected:
        return f"Blocked: {result.reasoning}"

    import subprocess

    output = subprocess.run(command, shell=True, capture_output=True, text=True)
    return output.stdout or output.stderr


llm_with_tools = llm.bind_tools([shell])


async def run_tools(state: State):
    last_message = state["messages"][-1]

    if not getattr(last_message, "tool_calls", None):
        return {}

    tool_messages: list[ToolMessage] = []
    for call in last_message.tool_calls:
        if call["name"] == "shell":
            result = await shell.ainvoke(call["args"])
            tool_messages.append(
                ToolMessage(content=result, tool_call_id=call["id"])
            )

    return {"messages": tool_messages}

Complete workflow with tools

python title="agent.py"
from typing import Literal


def should_use_tools(state: State) -> Literal["tools", "end"]:
    last_message = state["messages"][-1]
    if getattr(last_message, "tool_calls", None):
        return "tools"
    return "end"


tool_workflow = StateGraph(State)

tool_workflow.add_node("guard", guard_input)


async def generate_with_tools(state: State):
    if state.get("blocked", False):
        return {}
    response = await llm_with_tools.ainvoke(state["messages"])
    return {"messages": [response]}


tool_workflow.add_node("generate", generate_with_tools)

tool_workflow.add_node("tools", run_tools)

tool_workflow.set_entry_point("guard")
tool_workflow.add_edge("guard", "generate")
tool_workflow.add_conditional_edges("generate", should_use_tools, {
    "tools": "tools",
    "end": END,
})
tool_workflow.add_edge("tools", "generate")

agent = tool_workflow.compile()

Use the agent

python title="main.py"
async def main():
    result = await app.ainvoke({
        "messages": [HumanMessage(content="Hello!")],
        "blocked": False,
    })
    print(result["messages"][-1].content)

    agent_response = await agent.ainvoke({
        "messages": [HumanMessage(content="List files in current directory")],
        "blocked": False,
    })
    print(agent_response["messages"][-1].content)

    async for chunk in agent.astream({
        "messages": [HumanMessage(content="What's in the README?")],
        "blocked": False,
    }):
        print(chunk)

    result = await guard("delete all files")
    if result.decision.status == "block":
        print("Violations:", result.decision.violation_types)
        print("CWE codes:", result.decision.cwe_codes)

    await guard.aclose()


asyncio.run(main())

Key concepts

Both language implementations follow the same pattern:

  1. Guard node validates user input before it reaches the LLM.
  2. Generate node creates responses only after the guard passes.
  3. Tools node executes guarded tools and feeds their results into the state.
  4. State management tracks conversation history plus blocked status.
  5. Conditional routing decides whether to loop through tools or finish.

The guard enforces safety at every hop: prompts are checked pre-LLM, tool inputs are screened before execution, and tool outputs can be filtered before returning to the user.


Content/Docs/Legacy/Agent Frameworks/Mastra


title: Mastra AI

Superagent provides enterprise-grade security validation for Mastra AI agents through custom processors. This guide shows you how to use Mastra's processor interface to implement input validation and output redaction with Superagent Guard.

Overview

Mastra's processor interface allows you to intercept and transform messages before they reach your agent (input processors) and after the agent generates responses (output processors). By integrating Superagent Guard through custom processors, you can:

  • Validate all user inputs automatically before they reach your AI model
  • Redact sensitive information from agent responses (PII, PHI, credentials, etc.)
  • Block malicious content with detailed security analysis
  • Handle security violations with custom error handling via TripWire

Prerequisites

Before starting, ensure you have:

  • Node.js v20.0 or higher
  • A Superagent account with API key (sign up here)
  • An OpenAI API key or other LLM provider credentials
  • Basic familiarity with Mastra agents

Installation

Install the required dependencies:

bash title="terminal"
npm install @mastra/core superagent-ai zod @ai-sdk/openai
# or
pnpm add @mastra/core superagent-ai zod @ai-sdk/openai
# or
yarn add @mastra/core superagent-ai zod @ai-sdk/openai

Configuration

Setting up environment variables

Create a .env file in your project root:

bash title=".env"
SUPERAGENT_API_KEY=your_superagent_api_key
OPENAI_API_KEY=your_openai_api_key

Initialize the Superagent client

typescript title="guard.ts"
import { createGuard } from 'superagent-ai';

const guard = createGuard({
  apiBaseUrl: 'https://app.superagent.sh/api/guard', // optional for self-hosted
  apiKey: process.env.SUPERAGENT_API_KEY!,
});

Custom Processors for Security

Input Processor: Validating User Messages

Mastra provides a Processor interface that allows you to validate and transform messages before they reach your agent. Create a custom input processor that integrates Superagent Guard for automatic security validation:

typescript title="guard-input-processor.ts"
import type { Processor } from "@mastra/core/processors";
import type { MastraMessageV2 } from "@mastra/core/agent/message-list";
import { TripWire } from "@mastra/core/agent";

class SuperagentGuardProcessor implements Processor {
  readonly name = 'superagent-guard';

  async processInput({ messages, abort }: {
    messages: MastraMessageV2[];
    abort: (reason?: string) => never
  }): Promise<MastraMessageV2[]> {
    try {
      // Extract text content from all messages
      const textContent = messages
        .flatMap(msg => msg.content.parts)
        .filter(part => part.type === 'text')
        .map(part => (part as any).text)
        .join('\n');

      // Guard the content
      const { rejected, reasoning, decision } = await guard(textContent);

      if (rejected) {
        abort(`Guard blocked content: ${reasoning}`);
      }
    } catch (error) {
      if (error instanceof TripWire) {
        throw error; // Re-throw tripwire errors
      }
      throw new Error(`Guard validation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
    }

    return messages;
  }
}

// Use with your agent
const agent = new Agent({
  inputProcessors: [
    new SuperagentGuardProcessor(),
  ],
});

Output Processor: Redacting Sensitive Information

Output processors allow you to intercept and modify AI responses before they're returned to users. Create a custom output processor that uses Superagent's redaction capabilities to automatically remove sensitive information:

text
/* Detailed source-code truncated for AI context efficiency. */

Combining Input and Output Processors

Combine both processors for complete protection with input validation and output redaction:

typescript title="secure-agent.ts"
import { Agent } from '@mastra/core';

const agent = new Agent({
  inputProcessors: [
    new SuperagentGuardProcessor(), // Validate all inputs before processing
  ],
  outputProcessors: [
    new SuperagentRedactionProcessor(), // Redact sensitive data from outputs
  ],
});

This setup ensures that:

  • All user inputs are validated for security threats before reaching the agent
  • All agent outputs are automatically redacted to remove PII, credentials, and other sensitive data
  • Security violations are handled gracefully with TripWire error handling

Content/Docs/Legacy/Agent Frameworks/Openai Agents Sdk


title: OpenAI Agents SDK

Overview

The OpenAI Agents SDK provides a simple way to build AI agents with function calling capabilities. When these agents interact with users and execute tools, security becomes critical. Superagent adds a security layer that:

  • Validates user inputs before they reach your agent
  • Guards tool executions to prevent harmful operations
  • Redacts sensitive information from agent outputs (PII, PHI, credentials)
  • Provides detailed security analysis with violation detection

Prerequisites

Before starting, ensure you have:

  • Python 3.10 or higher
  • A Superagent account with API key (sign up here)
  • An OpenAI API key
  • Basic familiarity with OpenAI Agents SDK

Installation

Install the required dependencies:

bash title="terminal"
uv add superagent-ai openai-agents-sdk

Configuration

Setting up environment variables

Create a .env file in your project root:

bash title=".env"
SUPERAGENT_API_KEY=your_superagent_api_key
OPENAI_API_KEY=your_openai_api_key

Initialize the Superagent client

python title="config.py"
import os
from superagent_ai import create_client

# Initialize Superagent client
superagent = create_client(
    api_key=os.getenv("SUPERAGENT_API_KEY"),
)

Basic Agent with Guard Protection

Protect your agent by validating user inputs before processing:

text
/* Detailed source-code truncated for AI context efficiency. */

Advanced: Guarded Tools

Protect individual tool executions by validating tool parameters:

text
/* Detailed source-code truncated for AI context efficiency. */

Output Redaction

Automatically redact sensitive information from agent responses:

text
/* Detailed source-code truncated for AI context efficiency. */

Complete Example: Input Guard + Output Redaction

Combine both guard and redact for comprehensive protection:

text
/* Detailed source-code truncated for AI context efficiency. */

Stream Mode with Security

Handle streaming responses with redaction:

text
/* Detailed source-code truncated for AI context efficiency. */

Error Handling

Handle guard and redact errors gracefully:

text
/* Detailed source-code truncated for AI context efficiency. */

Key Concepts

The integration pattern follows these principles:

  1. Input Validation: Guard user inputs before they reach your agent to prevent malicious prompts, injections, and harmful instructions.

  2. Tool Protection: Validate tool parameters before execution to prevent dangerous operations like system modifications or data deletion.

  3. Output Redaction: Automatically remove PII, PHI, credentials, and other sensitive data from agent responses before returning them to users.

  4. Layered Security: Combine guard and redact for defense-in-depth: validate inputs, execute safely, and sanitize outputs.

  5. Error Handling: Gracefully handle security violations and API errors without exposing sensitive information.

  6. Async/Await Pattern: Both Superagent and OpenAI Agents SDK use async/await for non-blocking operations.

For more details on the Superagent Python SDK, see the Python SDK documentation.


Content/Docs/Legacy/Agent Frameworks/Pydantic Ai


title: Pydantic AI

Overview

Pydantic AI is a Python agent framework designed to make it easier to build production-grade applications with Generative AI. When building AI agents that execute tools and handle sensitive data, security is critical. Superagent adds a security layer that:

  • Validates user inputs before they reach your agent
  • Guards tool executions to prevent harmful operations
  • Redacts sensitive information from agent outputs (PII, PHI, credentials)
  • Provides detailed security analysis with violation detection

Prerequisites

Before starting, ensure you have:

  • Python 3.10 or higher
  • A Superagent account with API key (sign up here)
  • An OpenAI API key (or other LLM provider)
  • Basic familiarity with Pydantic AI

Installation

Install the required dependencies:

bash title="terminal"
uv add superagent-ai pydantic-ai httpx

Configuration

Setting up environment variables

Create a .env file in your project root:

bash title=".env"
SUPERAGENT_API_KEY=your_superagent_api_key
OPENAI_API_KEY=your_openai_api_key

Basic Agent with Guard Protection

Protect your agent by validating user inputs before processing:

text
/* Detailed source-code truncated for AI context efficiency. */

Advanced: Database Agent with Guard

Protect database operations by validating queries before execution:

text
/* Detailed source-code truncated for AI context efficiency. */

Output Redaction

Automatically redact sensitive information from agent responses:

text
/* Detailed source-code truncated for AI context efficiency. */

Complete Example: Input Guard + Output Redaction

Combine both guard and redact for comprehensive protection:

text
/* Detailed source-code truncated for AI context efficiency. */

Streaming Responses with Security

Handle streaming responses with guard and redaction:

text
/* Detailed source-code truncated for AI context efficiency. */

Error Handling

Handle guard and redact errors gracefully:

text
/* Detailed source-code truncated for AI context efficiency. */

Key Concepts

The integration pattern follows these principles:

  1. Input Validation: Guard user inputs before they reach your agent to prevent malicious prompts, SQL injection, path traversal, and harmful instructions.

  2. Tool Protection: Validate tool parameters (queries, commands, file paths) before execution to prevent dangerous operations like system modifications or data deletion.

  3. Output Redaction: Automatically remove PII, PHI, credentials, IP addresses, and other sensitive data from agent responses before returning them to users.

  4. Dependency Injection: Use Pydantic AI's deps_type to inject the Superagent client into your tools, allowing guard and redact operations within tool functions.

  5. Layered Security: Combine guard and redact for defense-in-depth: validate inputs, execute safely, and sanitize outputs.

  6. Error Handling: Gracefully handle security violations and API errors without exposing sensitive information.

  7. Streaming Support: Pydantic AI's streaming capabilities work seamlessly with Superagent - collect the full output, then redact before displaying to users.

For more details on the Superagent Python SDK, see the Python SDK documentation.


Content/Docs/Legacy/Agent Frameworks/Vercel Ai Sdk


title: Vercel AI SDK

Superagent lets you keep the Vercel AI SDK workflow you already use while inserting safety checks for every prompt and tool invocation. The TypeScript SDK is a lightweight client that calls your Superagent Guard endpoint and returns structured allow/block decisions.

Overview

When building AI agents that can execute commands, access files, or interact with external systems, security is paramount. Superagent acts as a security layer that:

  • Validates user prompts before they reach your AI model
  • Guards tool executions to prevent harmful operations
  • Filters tool outputs to ensure safe content handling
  • Provides detailed security analysis with CWE codes and violation types

Prerequisites

Before starting, ensure you have:

  • Node.js v20.0 or higher
  • A Superagent account with API key (sign up here)
  • An OpenAI API key or other LLM provider credentials
  • Basic familiarity with Vercel AI SDK

Install dependencies

If you have not already added the Guard SDK to your project:

bash title="terminal"
npm install superagent-ai
# or
pnpm add superagent-ai
# or
yarn add superagent-ai

The rest of this guide assumes you already have the Vercel AI SDK configured (for example ai, @ai-sdk/openai, and zod).

Configure the guard client and provider

ts title="guard.ts"
import { createGuard } from "superagent-ai";
import { createOpenAI } from "@ai-sdk/openai";
import { generateText } from "ai";

const guard = createGuard({
  apiBaseUrl: "https://app.superagent.sh/api/guard", // optional for self-hosted
  apiKey: process.env.SUPERAGENT_API_KEY!,
});

createGuard returns a callable function you can run before the Vercel AI SDK sends a prompt or executes a tool. The guard response contains a decision object (pass/block), optional violation metadata, and a human readable reasoning string.

Guard user inputs before generating text

Call the guard function when you receive user text. Only forward the prompt to the model if the guard status is pass.

ts title="generate.ts"
export async function generateGuardedText(userPrompt: string): Promise<GuardedResponse> {
  const { decision, reasoning, rejected } = await guard(userPrompt, {
    onBlock: () => console.warn("Blocked prompt:", reasoning),
    onPass: () => console.log("Prompt cleared guard"),
  });

  if (rejected) {
    return {
      text: null,
      safetyAnalysis: {
        decision,
        reasoning
      }
    };
  }

  const { text } = await generateText({
    model: openai("gpt-4o-mini"),
    prompt: userPrompt,
  });

  return {
    text,
    safetyAnalysis: {
      decision,
      reasoning
    }
  };
}

You can surface back reasoning and decision to your user interface, log it for audit purposes, or trigger a fallback experience. The same guard check can run inside handleSubmit with useChat or any server action that frames messages before calling generateText/streamText.

Guard tool execution

When you expose tools (for example shell access, file I/O, or network requests) wrap the tool body with the guard before performing the action.

ts title="tool.ts"
import { streamText, tool } from "ai";
import { z } from "zod";
import { createGuard } from "superagent-ai";

const guard = createGuard({ apiKey: process.env.SUPERAGENT_API_KEY })

const runCommand = tool({
  description: "Execute a shell command",
  inputSchema: z.object({
    command: z.string().describe("The shell command to execute"),
  }),
  execute: async ({ command }) => {
    const { decision, reasoning, rejected } = await guard(command, {
      onBlock: () => console.warn("Tool call blocked:", reasoning),
    });

    if (rejected) {
      return {
        result: null,
        safetyAnalysis: {
          decision,
          reasoning
        }
      };
    }

    const result = await runShellCommand(command);

    return {
      result,
      safetyAnalysis: {
        decision,
        reasoning
      }
    }
  },
});

const result = await streamText({
  model: openai("gpt-5"),
  prompt: "Inspect the repository and summarize the README.",
  tools: { runCommand },
});

The guard prevents the AI from executing unsafe commands while still allowing compliant tool calls to continue. You can return a structured object when the guard blocks a call so the model can recover gracefully or inform the user.

Guard tool results

You can also vet the data returned by a tool before handing it back to the model. The example below uses Firecrawl to scrape a page, then runs the combined crawl output through Guard so unsafe content never reaches the agent loop.

text
/* Detailed source-code truncated for AI context efficiency. */

When Guard blocks the crawl result, the tool returns a safetyAnalysis payload instead of the scraped data. The agent can then ask the user for a different URL, try a fallback provider, or skip the unsafe step entirely.


Content/Docs/Legacy/Examples/Claude Code Userprompt


title: Superagent + Claude Code Hooks

Introduction

Claude Code is a powerful AI coding assistant that can execute commands, read files, and make changes to your codebase. While this autonomy is incredibly useful, it also introduces potential security risks. What if a malicious prompt tricks Claude into executing dangerous commands? What if sensitive data accidentally gets exposed?

This is where Superagent comes in. By integrating Superagent with Claude Code's hooks system, you can validate every prompt before Claude processes it, blocking malicious or dangerous requests automatically.

In this guide, we'll walk through building a complete security solution using Claude Code's UserPromptSubmit hook and the Superagent API.

Prerequisites

Before you begin, you'll need:

  1. Superagent Account: Sign up at app.superagent.sh
  2. API Key: Once logged in, navigate to your dashboard and create a new API key (format: sa_...)
  3. Claude Code: Installed and running on your machine
  4. Node.js: Version 18 or higher for running the CLI

What are Claude Code Hooks?

Claude Code hooks are custom scripts that execute at specific points in the Claude Code lifecycle. They allow you to:

  • Validate prompts before Claude processes them
  • Add context to prompts automatically
  • Block dangerous operations before they execute
  • Log and audit all interactions

The UserPromptSubmit hook specifically fires whenever a user sends a prompt to Claude, making it the perfect place to implement security checks.

Configure Claude Code

Step 1: Install Superagent CLI

bash title="terminal"
npm i safety-agent-cli

Step 2: Hook Configuration Format

Claude Code hooks are configured in ~/.claude/settings.json. Here's the complete configuration:

json title="~/.claude/settings.json"
{
  "env": {
    "SUPERAGENT_API_KEY": "your_api_key_here"
  },
  "hooks": {
    "UserPromptSubmit": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "superagent guard"
          }
        ]
      }
    ]
  }
}

Step 3: Restart Claude Code

Close and reopen Claude Code to load the new configuration.

How It Works

  1. User sends a prompt to Claude Code
  2. Claude Code triggers the hook before processing the prompt
  3. Hook passes JSON to CLI via stdin:
    json title="hook input"
    {
      "prompt": "User's prompt text here",
      "session_id": "abc123",
      "cwd": "/current/working/dir"
    }
  4. CLI validates the prompt with SuperagentLM
  5. CLI returns decision as JSON:
    • If blocked: Returns {"decision": "block", "reason": "..."}
    • If allowed: Returns success (exit code 0)
  6. Claude Code processes the result:
    • Blocked prompts are rejected with the reason shown to user
    • Allowed prompts proceed normally

Next Steps

  • Explore PreToolUse hooks to validate Bash commands before execution
  • Build custom validators for your specific security policies
  • Integrate with SIEM for enterprise security monitoring
  • Create team policies with shared hook configurations

Happy coding, and stay secure! πŸ›‘οΈ


Resources


Content/Docs/Legacy/Examples/E2b


title: Secure E2B sandboxes

Superagent lets you screen model‑generated code before it reaches an E2B sandbox. This example shows how to connect OpenAI with E2B's Code Interpreter, adding a security layer that vets all code before execution.

Why combine Superagent + E2B

  • Superagent rejects malicious code (data exfiltration, destructive commands, cryptocurrency mining) before any process starts.
  • E2B provides secure, isolated Python environments for executing AI-generated code.
  • Together you get defense‑in‑depth: pre‑execution safety + runtime isolation.

Python

Install dependencies:

bash title="terminal"
pip install openai e2b-code-interpreter superagent-ai

Here's how to connect OpenAI with E2B Code Interpreter and guard the generated code:

python title="guarded-code-runner.py"
import asyncio
from openai import OpenAI
from e2b_code_interpreter import Sandbox
from superagent_ai import create_client

async def main():
    # Initialize clients
    openai_client = OpenAI()
    superagent_client = create_client(
        api_key="sk-...",
    )

    # Configure the system prompt
    system = "You are a helpful assistant that can execute python code in a Jupyter notebook. Only respond with the code to be executed and nothing else."
    prompt = "Calculate how many r's are in the word 'strawberry'"

    # Send messages to OpenAI API
    response = openai_client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {"role": "system", "content": system},
            {"role": "user", "content": prompt}
        ]
    )

    # Extract the code from the response
    code = response.choices[0].message.content

    # 1) Guard the generated code
    guard_result = await superagent_client.guard(code)
    if guard_result.rejected:
        print(f"⚠️  Blocked: {guard_result.reasoning}")
    else:
        # 2) Execute code in E2B Sandbox
        with Sandbox.create() as sandbox:
            execution = sandbox.run_code(code)
            result = execution.text
            print(result)

    await superagent_client.aclose()

asyncio.run(main())

Function calling with guarded execution

For more advanced use cases with function calling, define a tool that guards code before execution:

text
/* Detailed source-code truncated for AI context efficiency. */

TypeScript

Install dependencies:

bash title="terminal"
npm install openai e2b-code-interpreter superagent-ai

Here's how to connect OpenAI with E2B Code Interpreter using TypeScript:

ts title="guarded-code-runner.ts"
import OpenAI from "openai";
import { Sandbox } from "e2b-code-interpreter";
import { createClient } from "superagent-ai";

// Initialize clients
const openai = new OpenAI();
const client = createClient({
  apiKey: process.env.SUPERAGENT_API_KEY!,
});

async function runGuardedCode() {
  // Configure the system prompt
  const system = "You are a helpful assistant that can execute python code in a Jupyter notebook. Only respond with the code to be executed and nothing else.";
  const prompt = "Calculate how many r's are in the word 'strawberry'";

  // Send messages to OpenAI API
  const response = await openai.chat.completions.create({
    model: "gpt-4o",
    messages: [
      { role: "system", content: system },
      { role: "user", content: prompt }
    ]
  });

  // Extract the code from the response
  const code = response.choices[0].message.content!;

  // 1) Guard the generated code
  const { rejected, reasoning } = await client.guard(code);

  if (rejected) {
    console.log(`⚠️  Blocked: ${reasoning}`);
    return;
  }

  // 2) Execute code in E2B Sandbox
  const sandbox = await Sandbox.create();
  try {
    const execution = await sandbox.runCode(code);
    console.log(execution.text);
  } finally {
    await sandbox.close();
  }
}

runGuardedCode();

Function calling with guarded execution

For more advanced use cases with function calling:

text
/* Detailed source-code truncated for AI context efficiency. */

Security best practices

  • Always guard code before execution to catch malicious patterns.
  • Use E2B's isolated sandbox environments to prevent system access.
  • Keep audit logs of guard decisions and execution results.
  • Set appropriate timeouts for code execution.
  • Monitor and handle execution errors gracefully.

This pattern gives you a simple, repeatable way to safely execute AI‑generated code with layered protections.


Content/Docs/Legacy/Examples/Firecrawl


title: Secure search agent with Firecrawl

TL;DR: In this post, you’ll ship a tiny but production-ready web-search agent that crawls pages with Firecrawl and uses Superagent Guard to: (1) vet user queries, (2) scan fetched content for prompt injection and unsafe patterns, and (3) gate follow-on tool actions. Defense-in-depth for retrieval in ~50 lines.


Why this matters

LLM browsing agents can be tricked by prompt injection, malicious HTML/JS, and social-engineering embedded in page text. The safest baseline is to treat all web input as untrusted and enforce checks at every boundary:

  1. Before you browse: validate user prompts/URLs.
  2. During browsing: sanitize and screen the fetched content.
  3. After browsing: restrict any outbound actions unless they pass a policy.

This tutorial shows how to add those controls around Firecrawl’s official JS SDK.


What you’ll build

A minimal web-search agent using the AI SDK cookbook pattern. It exposes a webSearch tool that:

  • Accepts a URL
  • Uses Superagent Guard to approve the fetch
  • Crawls via Firecrawl (markdown or HTML)
  • Screens the returned content again with the guard
  • Returns safe text back to the model

You’ll also guard the initial user prompt so clearly malicious requests never reach the model.


Prerequisites

bash title="terminal"
npm install ai @ai-sdk/openai superagent-ai zod @mendable/firecrawl-js dotenv

Set environment variables (e.g. in a .env file or your shell):

bash title=".env"
export OPENAI_API_KEY=sk-openai-...
export SUPERAGENT_API_KEY=sk-superagent-...
export FIRECRAWL_API_KEY=fc-...

Create a secure web search agent using Firecrawl and Vercel AI SDK

Below is a complete runnable script. It mirrors the AI SDK β€œweb-search agent” pattern and adds Superagent before/after the crawl.

text
/* Detailed source-code truncated for AI context efficiency. */

How it works (line by line)

Step 1 β€” Client creation

Use createClient with your Superagent API key. Pass text to client.guard() whenever you want to vet it. A rejected result includes a reasoning string.

Step 2 β€” Guarding URLs

Prefix the string with FETCH: so your guard policy can treat URL fetches differently than general text.

Step 3 β€” Crawling with Firecrawl

crawlUrl() fetches and converts the page. Here we request markdown and html and prefer markdown when available.

Step 4 β€” Content screening

Guard the returned text again before passing to the LLM. This blocks prompt injection and unsafe patterns.

Step 5 β€” Budgeting agent steps

Use stepCountIs(5) to prevent infinite loops.


Content/Docs/Legacy/Examples/Mastra


title: Secure Mastra with Superagent

TL;DR: In this post, you’ll set up a Mastra agent hardened with Superagent. You’ll: (1) validate all user inputs before they reach your agent, (2) redact sensitive information from outputs, and (3) gracefully handle violations via Mastra processors. Defense-in-depth for production agents in ~60 lines.

Why this matters

LLM apps often face two classes of risks:

  • Inbound threats: malicious or unsafe prompts, prompt injection, and attempts to bypass policies.
  • Outbound risks: leaking sensitive data (PII, API keys, credentials) in generated responses.

By combining Mastra’s processor interface with Superagent, you can enforce security checks at both boundaries:

  1. Before input hits the model β†’ Validate, sanitize, or block unsafe prompts.
  2. After the model responds β†’ Automatically redact sensitive tokens and apply TripWire policies.

This pattern lets you build safer, production-ready agents without changing your core logic.


What you’ll build

A minimal Mastra agent that:

  • Uses an input processor to guard user prompts.
  • Uses an output processor to redact sensitive information.
  • Handles violations via Mastra’s TripWire.

Prerequisites

bash title="terminal"
npm install @mastra/core superagent-ai zod @ai-sdk/openai

Set your environment variables:

bash title=".env"
SUPERAGENT_API_KEY=sk-superagent-...
OPENAI_API_KEY=sk-openai-...

Step 1 β€” Create a Superagent client

typescript title="client.ts"
import { createClient } from 'superagent-ai';

export const client = createClient({
  apiKey: process.env.SUPERAGENT_API_KEY!,
});

Step 2 β€” Input Processor: Validate Messages

typescript title="guard-input-processor.ts"
import type { Processor } from "@mastra/core/processors";
import type { MastraMessageV2 } from "@mastra/core/agent/message-list";
import { TripWire } from "@mastra/core/agent";
import { client } from "./client";

class SuperagentGuardProcessor implements Processor {
  readonly name = 'superagent-guard';

  async processInput({ messages, abort }: {
    messages: MastraMessageV2[];
    abort: (reason?: string) => never
  }): Promise<MastraMessageV2[]> {
    const text = messages
      .flatMap(m => m.content.parts)
      .filter(p => p.type === 'text')
      .map((p: any) => p.text)
      .join('\n');

    const { rejected, reasoning } = await client.guard(text);

    if (rejected) abort(`Blocked by guard: ${reasoning}`);
    return messages;
  }
}

Step 3 β€” Output Processor: Redact Sensitive Data

typescript title="redaction-output-processor.ts"
import type { Processor } from "@mastra/core/processors";
import type { MastraMessageV2 } from "@mastra/core/agent/message-list";
import { TripWire } from "@mastra/core/agent";
import { createClient } from "superagent-ai";

const client = createClient({
  apiKey: process.env.SUPERAGENT_API_KEY!,
});

class SuperagentRedactionProcessor implements Processor {
  readonly name = 'superagent-redaction';

  async processOutputResult({ messages, abort }: {
    messages: MastraMessageV2[];
    abort: (reason?: string) => never
  }): Promise<MastraMessageV2[]> {
    return Promise.all(messages.map(async (msg) => {
      const newParts = await Promise.all(
        msg.content.parts.map(async (part: any) => {
          if (part.type === 'text') {
            // First guard the output
            const guardResult = await client.guard(part.text);
            if (guardResult.rejected) abort(`Output blocked: ${guardResult.reasoning}`);

            // Then redact sensitive information
            const redactResult = await client.redact(part.text);
            return { ...part, text: redactResult.redacted };
          }
          return part;
        })
      );
      return { ...msg, content: { ...msg.content, parts: newParts } };
    }));
  }
}

Step 4 β€” Combine Processors in Your Agent

typescript title="secure-agent.ts"
import { Agent } from '@mastra/core';

const agent = new Agent({
  inputProcessors: [new SuperagentGuardProcessor()],
  outputProcessors: [new SuperagentRedactionProcessor()],
});

How it works

  1. Input validation β€” All user prompts pass through SuperagentGuardProcessor. Unsafe prompts are blocked with detailed reasoning.
  2. Output redaction β€” Every generated response is scanned. PII, secrets, and other sensitive info are automatically removed.
  3. TripWire handling β€” Violations can trigger safe aborts and custom error handling.

Takeaways

  • Mastra’s processor hooks make it easy to enforce security-by-default.
  • Superagent adds policy enforcement and redaction without custom regexes.
  • This pattern scales across agents, models, and teams.


Content/Docs/Legacy/Examples/N8n Redact


title: Guardrails in n8n with Superagent

This post shows the pattern we ship for the Email Triage Agent template in n8n. We insert a Superagent Redact call between the Gmail trigger and the classifier so every message is cleaned before the model sees it.

Prerequisites

Before you start, you'll need:

  1. An n8n account (cloud or self-hosted)
  2. A Superagent account and API key

The pattern

Gmail Trigger β†’ HTTP Request (Superagent Redact) β†’ Email Classification β†’ Gmail label actions

What you get:

  • PII is scrubbed before inference
  • Prompts stay stable
  • Logs are safer to store and share

Why Superagent Redact

  • Targets common PII like emails, phones, addresses, URLs
  • Simple REST API
  • Works as a drop-in guardrail for any text step

Drop-in wiring in the template

Start from the Email Triage Agent in n8n.

Add one HTTP Request node between the trigger and the classifier. Configure:

  • Method: POST

  • URL: https://app.superagent.sh/api/redact

  • Auth: Bearer SUPERAGENT_API_KEY

  • Body JSON:

    json title="http request body"
    {
      "text": "{{$json.text}}"
    }

Here is the node in context:

Point your Email Classification prompt to the HTTP node output:

text title="email classification prompt"
Categorize this email:

**From:** {{ $('New Email Trigger').item.json.from.value[0].address }}
**Subject:** {{ $('New Email Trigger').item.json.subject }}
**Content:**
{{ $json.choices[0].message.content }}

Please analyze this email and apply appropriate labels using the available tools.

Test it

Send a test email with real PII to your Gmail account:

text title="test email content"
My phone is 555-123-4567 and you can email me at [email protected].
I live at 123 Main Street, New York, NY 10001.

Check the execution log in the HTTP Request node. The redacted output should look like:

text title="redacted output"
My phone is [PHONE_REDACTED] and you can email me at [EMAIL_REDACTED].
I live at [ADDRESS_REDACTED].

Your classifier sees clean text, but the workflow still routes the email correctly.

What you've protected

  • Customer support logs no longer leak PII
  • Model prompts stay consistent without random customer data
  • Compliance audits get cleaner (GDPR, HIPAA, SOC 2)
  • You can share workflow exports without scrubbing test data

Next steps



Content/Docs/Legacy/Examples/Redact Pdfs


title: Redact PDFs in seconds