> ## Documentation Index
> Fetch the complete documentation index at: https://docs.verifiedx.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Claude Agent SDK

> Attach VerifiedX to the Claude Agent SDK query surface in Python or TypeScript.

**Best for:** teams already using the Claude Agent SDK and wanting native protection without changing runtimes.

<Note>
  Run doctor in the repo before you wire anything:

  * TypeScript: `npx @verifiedx-core/sdk doctor`
  * Python: `verifiedx doctor`

  Protect one action free: [verifiedx.me](https://verifiedx.me/?vx_source=docs.claude-agent-sdk)

  If doctor shows a different native adapter already owns the tool loop, switch to that page before integrating.
</Note>

## Install

<CodeGroup>
  ```bash Python theme={null}
  pip install verifiedx
  ```

  ```bash TypeScript theme={null}
  npm install @verifiedx-core/sdk
  ```
</CodeGroup>

<Note>
  This page assumes your app already uses `claude_agent_sdk` in Python or `@anthropic-ai/claude-agent-sdk` in TypeScript.
</Note>

## Net-new VerifiedX code

This is the actual VerifiedX delta in an existing Claude Agent SDK query setup.

<CodeGroup>
  ```python Python theme={null}
  from verifiedx import claude_query, init_verifiedx

  verifiedx = init_verifiedx()

  async for message in claude_query(
      prompt=prompt,
      verifiedx=verifiedx,
      options=options,
  ):
      ...
  ```

  ```typescript TypeScript theme={null}
  import { initVerifiedX } from "@verifiedx-core/sdk";
  import { withVerifiedXClaudeQuery } from "@verifiedx-core/sdk/claude-agent";

  const verifiedx = await initVerifiedX();
  const verifiedxQuery = await withVerifiedXClaudeQuery(claudeQuery, { verifiedx });

  for await (const message of verifiedxQuery({ prompt, options })) {
    console.log(message);
  }
  ```
</CodeGroup>

<Note>
  That is the important part. Your existing prompt, tools, MCP servers, system prompt, permission mode, and max-turn configuration stay the same.
</Note>

<Note>
  In Python, if you prefer to wrap an existing callable instead of swapping imports, use `attach_claude_query(...)`. In TypeScript, `withVerifiedXClaudeQuery(...)` is the wrapper surface.
</Note>

<Note>
  Your native tool surface is the config. VerifiedX uses your existing tool names, descriptions, schemas, MCP servers, built-ins, and approval flow as the source of truth for what to preflight.
</Note>

## Full example

<CodeGroup>
  ```python Python theme={null}
  import os

  from claude_agent_sdk import ClaudeAgentOptions, create_sdk_mcp_server, tool
  from verifiedx import claude_query, init_verifiedx

  @tool(
      "lookup_workflow",
      "Look up an internal workflow before changing state.",
      {"workflow_id": str},
  )
  async def lookup_workflow(args: dict[str, str]) -> dict:
      return {
          "content": [
              {
                  "type": "text",
                  "text": '{"ok": true, "workflow": {"workflow_id": "%s", "status": "pending_review"}}'
                  % args["workflow_id"],
              }
          ]
      }

  @tool(
      "set_workflow_status",
      "Update internal workflow status.",
      {"workflow_id": str, "status": str, "reason": str},
  )
  async def set_workflow_status(args: dict[str, str]) -> dict:
      return {
          "content": [
              {
                  "type": "text",
                  "text": (
                      '{"ok": true, "workflow_updated": {"workflow_id": "%s", "status": "%s", "reason": "%s"}}'
                      % (args["workflow_id"], args["status"], args["reason"])
                  ),
              }
          ]
      }

  support_ops = create_sdk_mcp_server(
      "support_ops",
      tools=[lookup_workflow, set_workflow_status],
  )

  verifiedx = init_verifiedx()

  options = ClaudeAgentOptions(
      tools=[],
      mcp_servers={"support_ops": support_ops},
      system_prompt="Use tools instead of prose for operational work.",
      permission_mode="bypassPermissions",
      model=os.environ.get("ANTHROPIC_MODEL", "claude-sonnet-4-6"),
      max_turns=20,
  )

  async for message in claude_query(
      prompt="CASE-7003: For workflow WF-1002, inspect it and then update it to awaiting_human because billing verification is missing.",
      verifiedx=verifiedx,
      options=options,
  ):
      print(message)
  ```

  ```typescript TypeScript theme={null}
  import { createSdkMcpServer, query as claudeQuery, tool } from "@anthropic-ai/claude-agent-sdk";
  import { z } from "zod";

  import { initVerifiedX } from "@verifiedx-core/sdk";
  import { withVerifiedXClaudeQuery } from "@verifiedx-core/sdk/claude-agent";

  const lookupWorkflow = tool(
    "lookup_workflow",
    "Look up an internal workflow before changing state.",
    {
      workflow_id: z.string(),
    },
    async ({ workflow_id }) => ({
      content: [
        {
          type: "text",
          text: JSON.stringify({
            ok: true,
            workflow: {
              workflow_id,
              status: "pending_review",
            },
          }),
        },
      ],
    }),
  );

  const setWorkflowStatus = tool(
    "set_workflow_status",
    "Update internal workflow status.",
    {
      workflow_id: z.string(),
      status: z.string(),
      reason: z.string(),
    },
    async ({ workflow_id, status, reason }) => ({
      content: [
        {
          type: "text",
          text: JSON.stringify({
            ok: true,
            workflow_updated: { workflow_id, status, reason },
          }),
        },
      ],
    }),
  );

  const supportOps = createSdkMcpServer({
    name: "support_ops",
    tools: [lookupWorkflow, setWorkflowStatus],
  });

  const verifiedx = await initVerifiedX();
  const verifiedxQuery = await withVerifiedXClaudeQuery(claudeQuery, { verifiedx });

  const options = {
    tools: [],
    mcpServers: { support_ops: supportOps },
    systemPrompt: "Use tools instead of prose for operational work.",
    permissionMode: "bypassPermissions",
    model: process.env.ANTHROPIC_MODEL || "claude-sonnet-4-6",
    maxTurns: 20,
  };

  for await (const message of verifiedxQuery({
    prompt: "CASE-8003: For workflow WF-1002, inspect it and then update it to awaiting_human because billing verification is missing.",
    options,
  })) {
    console.log(message);
  }
  ```
</CodeGroup>

<Note>
  Do not use raw `install_runtime(...)` or `bindHarness(...)` for this path. Keep the native Claude Agent SDK query surface and wrap that directly.
</Note>

## Composed systems

If this Claude run is part of a larger multi-agent or agent+human workflow, pass upstream context into VerifiedX so the current run has better system and situational awareness before it takes a high-impact action.

This is useful when a supervisor agent, parent workflow, or human reviewer already has context that the current Claude run should use before taking action.

VerifiedX does not require a fixed schema for this. Pass the upstream context you already have in any JSON-serializable shape.

<CodeGroup>
  ```python Python theme={null}
  upstream = {
      "source": "workflow_supervisor",
      "workflow_id": "WF-2203",
      "approval_status": "approved_with_follow_up",
      "human_review": {
          "reviewer": "ops_lead",
          "result": "approved",
      },
      "prior_agent_output": {
          "summary": "Billing verification is complete.",
      },
  }

  with verifiedx.with_upstream_context(upstream):
      async for message in claude_query(
          prompt=prompt,
          verifiedx=verifiedx,
          options=options,
      ):
          ...
  ```

  ```typescript TypeScript theme={null}
  const upstream = {
    source: "workflow_supervisor",
    workflow_id: "WF-2203",
    approval_status: "approved_with_follow_up",
    human_review: {
      reviewer: "ops_lead",
      result: "approved",
    },
    prior_agent_output: {
      summary: "Billing verification is complete",
    },
  };

  await verifiedx.withUpstreamContext(upstream, async () => {
    for await (const message of verifiedxQuery({ prompt, options })) {
      console.log(message);
    }
  });
  ```
</CodeGroup>

<Note>
  Upstream context is supporting workflow context from outside the current run. It is not proof that this run already executed any local action.
</Note>

## What the adapter already captures

Once attached, VerifiedX appends native Claude Agent SDK hooks into your existing query options and protects the SDK surface you already use.

That includes:

* Prompt submission through `UserPromptSubmit`
* Tool boundaries through `PreToolUse`, `PostToolUse`, and `PostToolUseFailure`
* Permission flow through `PermissionRequest` and `PermissionDenied`
* Stop events through `Stop`
* Lifecycle summaries through `Notification`, `PreCompact`, `SessionStart`, `SessionEnd`, `StopFailure`, `SubagentStart`, and `SubagentStop`
* Custom Claude Agent SDK tools and MCP-backed tools
* Mutating built-ins such as `Bash`, `Write`, `Edit`, `MultiEdit`, and `NotebookEdit` as direct protected boundaries
* Read-like built-ins such as `Read`, `Glob`, `Grep`, `WebFetch`, and `WebSearch` as support inputs in run history

`Read` stays a read-only support input here. It is captured truthfully as `file_read`, not misclassified as a memory write.

## What to expect at runtime

Protected boundaries can return:

* `allow`
* `allow_with_warning`
* `replan_required`
* `goal_fail_terminal`

Every outcome includes a structured decision receipt.

If a step is blocked during `PreToolUse`, VerifiedX returns native Claude hook output with a block decision and deny signal instead of throwing. The side effect does not execute, and Claude gets the reason plus safe-next-step guidance so it can keep moving toward the same goal when possible.

## Production-style validation coverage

The Claude Agent SDK validation paths in this repo cover real workflows including:

* Clean durable memory writes
* Clean record mutations
* Clean internal workflow updates
* Multi-step internal runs across retrieval, mutation, memory, and internal notification
* External email attempts that replan into safer internal Slack fallbacks
* Repeated adversarial external-email attempts that should not keep pushing the same unsafe action
* Built-in `Bash` local journal updates
* Built-in `Write` local note creation
* Built-in `Edit` local note mutation after a `Read` prerequisite step

## Pricing note

One protected action check equals one real boundary preflight. Taint, event ingest, execution reports, and decision reads are all included at that price. The Free Sandbox includes every language, provider, framework, and adapter.

VerifiedX does not replace your orchestrator or human workflow. It returns receipts your system can keep local, route downstream, or pass upstream.

***

For the raw runtime reference, see the [Python SDK](/sdks/python) and [TypeScript SDK](/sdks/typescript). For the direct Claude / Anthropic adapter outside the Claude Agent SDK, see the Anthropic pages.
