> ## 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.

# Anthropic / Claude

> Protect Claude Messages API tool use in Python or TypeScript.

**Best for:** teams using Claude through the Anthropic SDK directly.

<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.anthropic)

  If doctor shows a supported native adapter already owns the tool loop, use that page instead of the raw provider path.
</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 `anthropic` in Python or `@anthropic-ai/sdk` in TypeScript.
</Note>

## Net-new VerifiedX code

This is the actual VerifiedX delta in an existing Claude Messages tool loop.

<CodeGroup>
  ```python Python theme={null}
  from verifiedx import (
      attach_anthropic,
      create_anthropic_tool_dispatcher,
      init_verifiedx,
  )
  from verifiedx.anthropic_direct import (
      assistant_message_param as anthropic_assistant_message_param,
  )

  verifiedx = init_verifiedx()
  client = attach_anthropic(client, verifiedx=verifiedx)
  dispatch_tool_uses = create_anthropic_tool_dispatcher(
      verifiedx=verifiedx,
      tools=TOOLS,
      tool_handlers=HANDLERS,
  )

  # Inside your existing loop:
  messages.append(anthropic_assistant_message_param(message))
  tool_results = dispatch_tool_uses(message)
  if tool_results:
      messages.append({"role": "user", "content": tool_results})
  ```

  ```typescript TypeScript theme={null}
  import { initVerifiedX } from "@verifiedx-core/sdk";
  import {
    assistantMessageParam as anthropicAssistantMessageParam,
    attach as attachAnthropicDirect,
    createToolDispatcher as createAnthropicToolDispatcher,
  } from "@verifiedx-core/sdk/anthropic-direct";

  const verifiedx = await initVerifiedX();
  const client = await attachAnthropicDirect(client, { verifiedx });

  const dispatchToolUses = await createAnthropicToolDispatcher({
    verifiedx,
    tools: TOOLS,
    handlers: HANDLERS,
  });

  // Inside your existing loop:
  messages = [...messages, anthropicAssistantMessageParam(message)];
  const toolResults = await dispatchToolUses(message);
  if (toolResults.length > 0) {
    messages = [...messages, { role: "user", content: toolResults }];
  }
  ```
</CodeGroup>

<Note>
  That is the important part. The rest of the full example below is your normal Anthropic client, tool-definition, tool-handler, and message-loop code that you likely already have.
</Note>

<Note>
  Your native tool surface is the config. VerifiedX uses your existing tool names, descriptions, schemas, and native Claude Messages tool loop as the source of truth for what to preflight. If you want explicit `actions` and `memories` dictionaries, use the raw runtime instead.
</Note>

## Full example

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

  from anthropic import Anthropic
  from verifiedx import (
      attach_anthropic,
      create_anthropic_tool_dispatcher,
      init_verifiedx,
  )
  from verifiedx.anthropic_direct import (
      assistant_message_param as anthropic_assistant_message_param,
  )

  TOOLS = [
      {
          "name": "lookup_workflow",
          "description": "Look up an internal workflow before changing state.",
          "input_schema": {
              "type": "object",
              "properties": {"workflow_id": {"type": "string"}},
              "required": ["workflow_id"],
          },
      },
      {
          "name": "set_workflow_status",
          "description": "Update internal workflow status.",
          "input_schema": {
              "type": "object",
              "properties": {
                  "workflow_id": {"type": "string"},
                  "status": {"type": "string"},
                  "reason": {"type": "string"},
              },
              "required": ["workflow_id", "status", "reason"],
          },
      },
  ]

  def lookup_workflow(args):
      return {
          "ok": True,
          "workflow": {
              "workflow_id": args["workflow_id"],
              "status": "pending_review",
          },
      }

  def set_workflow_status(args):
      return {
          "ok": True,
          "workflow_updated": {
              "workflow_id": args["workflow_id"],
              "status": args["status"],
              "reason": args["reason"],
          },
      }

  verifiedx = init_verifiedx()
  client = attach_anthropic(
      Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"]),
      verifiedx=verifiedx,
  )

  dispatch_tool_uses = create_anthropic_tool_dispatcher(
      verifiedx=verifiedx,
      tools=TOOLS,
      tool_handlers={
          "lookup_workflow": lookup_workflow,
          "set_workflow_status": set_workflow_status,
      },
  )

  messages = [
      {
          "role": "user",
          "content": "Update workflow WF-1002 to awaiting_human because billing verification is missing.",
      }
  ]

  while True:
      message = client.messages.create(
          model="claude-sonnet-4-6",
          max_tokens=1200,
          system="Use tools instead of prose for operational work.",
          messages=messages,
          tools=TOOLS,
      )

      messages.append(anthropic_assistant_message_param(message))

      tool_results = dispatch_tool_uses(message)
      if not tool_results:
          break

      messages.append({"role": "user", "content": tool_results})
  ```

  ```typescript TypeScript theme={null}
  import Anthropic from "@anthropic-ai/sdk";
  import { initVerifiedX } from "@verifiedx-core/sdk";
  import {
    assistantMessageParam as anthropicAssistantMessageParam,
    attach as attachAnthropicDirect,
    createToolDispatcher as createAnthropicToolDispatcher,
  } from "@verifiedx-core/sdk/anthropic-direct";

  const TOOLS = [
    {
      name: "lookup_workflow",
      description: "Look up an internal workflow before changing state.",
      input_schema: {
        type: "object",
        properties: { workflow_id: { type: "string" } },
        required: ["workflow_id"],
      },
    },
    {
      name: "set_workflow_status",
      description: "Update internal workflow status.",
      input_schema: {
        type: "object",
        properties: {
          workflow_id: { type: "string" },
          status: { type: "string" },
          reason: { type: "string" },
        },
        required: ["workflow_id", "status", "reason"],
      },
    },
  ];

  const HANDLERS = {
    async lookup_workflow(args) {
      return {
        ok: true,
        workflow: {
          workflow_id: args.workflow_id,
          status: "pending_review",
        },
      };
    },

    async set_workflow_status(args) {
      return {
        ok: true,
        workflow_updated: {
          workflow_id: args.workflow_id,
          status: args.status,
          reason: args.reason,
        },
      };
    },
  };

  const verifiedx = await initVerifiedX();
  const client = await attachAnthropicDirect(
    new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY }),
    { verifiedx },
  );

  const dispatchToolUses = await createAnthropicToolDispatcher({
    verifiedx,
    tools: TOOLS,
    handlers: HANDLERS,
  });

  let messages = [
    {
      role: "user",
      content: "Update workflow WF-1002 to awaiting_human because billing verification is missing.",
    },
  ];

  while (true) {
    const message = await client.messages.create({
      model: "claude-sonnet-4-6",
      max_tokens: 1200,
      system: "Use tools instead of prose for operational work.",
      messages,
      tools: TOOLS,
    });

    messages = [...messages, anthropicAssistantMessageParam(message)];

    const toolResults = await dispatchToolUses(message);
    if (toolResults.length === 0) {
      break;
    }

    messages = [...messages, { role: "user", content: toolResults }];
  }
  ```
</CodeGroup>

<Note>
  Do not use raw `install_runtime(...)` or `bindHarness(...)` for this path. Keep the native Anthropic Messages API surface and use the Anthropic direct adapter.
</Note>

## Composed systems

If this Claude Messages loop 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 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):
      message = client.messages.create(
          model="claude-sonnet-4-6",
          max_tokens=1200,
          system="Use tools instead of prose for operational work.",
          messages=messages,
          tools=TOOLS,
      )

      tool_results = dispatch_tool_uses(message)
  ```

  ```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 () => {
    const message = await client.messages.create({
      model: "claude-sonnet-4-6",
      max_tokens: 1200,
      system: "Use tools instead of prose for operational work.",
      messages,
      tools: TOOLS,
    });

    const toolResults = await dispatchToolUses(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>

## Async tool handlers

If your tool handlers are async, use the async dispatcher in Python:

```python theme={null}
tool_results = await dispatch_tool_uses.async_dispatch(message)
```

In TypeScript, the dispatcher is already async:

```typescript theme={null}
const toolResults = await dispatchToolUses(message);
```

## Streaming

The adapter works with the normal Anthropic streaming surfaces too:

* `client.messages.create(...)`
* `client.messages.stream(...)`
* `client.messages.create(..., stream=True)` in Python
* `client.messages.create({ ..., stream: true })` in TypeScript

That includes native tool-history capture from streamed `tool_use` output while preserving the native stream shape.

## What the adapter already captures

Once attached, VerifiedX already captures and protects the native Anthropic Messages surface, including:

* Native `tool_use` history
* Native `server_tool_use` history
* Client-executed custom tools through the Anthropic tool dispatcher
* Built-in mutating memory, text-editor, and bash tool uses when present
* Prompt context from the Messages window across turns
* Normal continuation turns in direct tool loops
* Managed and raw streaming tool selections

Provider-executed server tools such as native web fetch, web search, code execution, and tool search stay in run history as native support inputs. You do not dispatch those yourself.

## 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 client-side tool is replanned, the side effect does not execute. The dispatcher returns Anthropic `tool_result` blocks containing the blocked result shape, including `ok: false`, `blocked: true`, `boundary_outcome`, `safe_next_steps`, and `decision_receipt`, so Claude can keep moving toward the same goal safely.

## 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 Claude Agent SDK surface, see the Claude Agent SDK page.
