Integrating Anthropic Claude

This is the canonical integration. The Verdifax SDK ships a one-call helper that takes a Claude prompt and response and returns a sealed manifest hash you can store alongside the model output.

Install

pip install verdifax anthropic

Two-call pattern

The simplest pattern: call Claude, then attest the result.

import anthropic
import verdifax

claude = anthropic.Anthropic()  # picks up ANTHROPIC_API_KEY

resp = claude.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Summarize this document..."}],
)
output = resp.content[0].text

receipt = verdifax.attest_claude_response(
    prompt="Summarize this document...",
    response=output,
    program_id="a" * 64,            # your registered program id
    route_id="claude-summarize-v1",
    registry_record_hash="b" * 64,  # your registry record hash
    govern=True,                    # route the output through AIVP-T4 review
)

print(f"Claude said: {output}")
print(f"Verdifax seal: {receipt.manifest_hash}")

receipt.manifest_hash is the artifact you keep. It names this one run: every call seals its own admission clock and per-run nonce, so attesting the same prompt and response again produces a new run with a different hash. What holds every time is that the run's sealed record still recomputes to the hashes it recorded.

What govern=True does, and why you want it

Without it, the attest call seals exactly what your code submitted, which proves submission, not that the model produced it or that the answer should have gone out. With govern=True (SDK 0.5.0+), the orchestrator routes the response text through the AIVP-T4 review stage: an independent reviewer model examines it and can refuse it, which halts the run before the execution record. The refusal is itself sealed and anchored on the public log as an AivpT4HaltReceipt; when the reviewer releases the output, the review outcome plus the governed-output hash become part of the sealed record. A governed run can therefore fail where an ungoverned one would quietly seal a bad answer; that is the point.

Two honest notes. Governance adds the review outcome and the governed-output hash to the sealed record, which changes what each run's manifest covers, so it is opt-in; treat turning it on as a format change. And the reviewer is a second model, not an oracle: its verdict is sealed evidence of an independent check, not a guarantee the answer is right, see What the Manifest Hash proves.

Payload canonicalization: helper-specific prefix

Important: The Claude helper uses a helper-specific canonicalization format. This is NOT the canonical format for raw verdifax.attest() calls.

Inside the helper, Verdifax canonicalizes the prompt + response with a Claude-specific prefix, joining the five parts with the ASCII record separator (\x1e); the blocks below show one part per line:

verdifax.helper.claude.v1
verdifax.helper.prompt.v1
<prompt>
verdifax.helper.response.v1
<response>

Example: If you call:

verdifax.attest_claude_response(
    prompt="What is 2+2?",
    response="4",
    ...
)

The payload the helper sends (parts joined by \x1e, shown one per line) is:

verdifax.helper.claude.v1
verdifax.helper.prompt.v1
What is 2+2?
verdifax.helper.response.v1
4

This means an identical prompt + response pair sent through attest_openai_response() produces a different manifest hash than through attest_claude_response(). That's intentional, the same text under different providers is meaningfully different evidence.

Without the helper

If you want to attest Claude calls without the helper's prefix, build the payload yourself:

payload = f"prompt:{prompt}\nresponse:{response}"
receipt = verdifax.attest(
    payload=payload,
    program_id="...",
    ...
)

This will hash the raw payload without any provider-specific prefix. You lose the provider separation but gain full control over what bytes are sealed.

Reusing a connection pool

For high-throughput servers, share one VerdifaxClient:

from verdifax import VerdifaxClient
import anthropic

claude = anthropic.Anthropic()
verdifax_client = VerdifaxClient()

def attest_one(prompt: str) -> str:
    resp = claude.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        messages=[{"role": "user", "content": prompt}],
    )
    output = resp.content[0].text
    receipt = verdifax.attest_claude_response(
        prompt=prompt,
        response=output,
        program_id="a" * 64,
        route_id="claude-summarize-v1",
        registry_record_hash="b" * 64,
        client=verdifax_client,
    )
    return receipt.manifest_hash

Async (FastAPI / async workers)

from verdifax import AsyncVerdifaxClient
import anthropic

claude = anthropic.AsyncAnthropic()

async def attest_async(prompt: str):
    resp = await claude.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        messages=[{"role": "user", "content": prompt}],
    )
    output = resp.content[0].text
    async with AsyncVerdifaxClient() as v:
        receipt = await v.attest(
            payload=f"prompt:{prompt}\nresponse:{output}",
            program_id="a" * 64,
            route_id="claude-summarize-v1",
            registry_record_hash="b" * 64,
        )
        return receipt.manifest_hash

What gets sealed

The helper sends Verdifax exactly two pieces of data: the prompt text and the response text. It does not send your Anthropic API key, conversation metadata, or system prompts. If you need those sealed too, build the payload yourself and call verdifax.attest() directly.

Continue