Your Claude integration produces sophisticated AI reasoning. Anthropic's RSP tracks model safety. Neither produces the inference-level evidence your compliance team needs.
v0.7.9 RELEASED – Anthropic adapter with streaming witnessing
Who this is for: ML engineers deploying Claude models, compliance leads managing AI risk, security teams integrating Claude into regulated workflows, and assessors evaluating Claude deployments.
Anthropic maintains one of the most rigorous safety frameworks in the industry (RSP). But RSP evaluates models at the training boundary -- not at your application boundary. When your Claude deployment processes a customer request, what evidence proves that specific inference was governed? Anthropic can tell you the model was safe to deploy. Only you can prove it was governed when it ran.
Anthropic provides substantial safety infrastructure for Claude models. The Responsible Scaling Policy (RSP) classifies models by capability level and applies corresponding safety commitments. Model cards document known limitations. Usage policies define acceptable use. This is the provider's responsibility, and Anthropic does it well.
But none of this addresses the deployer's evidence obligation. When your application calls Claude, you need proof that the specific inference was governed -- not that the model was generally safe when Anthropic evaluated it months ago.
| Anthropic Provides | You Need | Gap |
|---|---|---|
| RSP capability evaluations at training time | Per-inference evidence at runtime | No runtime evidence |
| Model cards with known limitations | Proof that limitations were managed in your deployment | No deployment-specific attestation |
| Usage policies and acceptable use terms | Evidence that your usage complied with those terms per call | No per-call compliance record |
| API response with model version string | Immutable record tying model version to specific input/output | API logs are mutable |
| Safety training (Constitutional AI, RLHF) | Evidence that safety training held for your specific use case | No use-case-specific evidence |
| System prompt support (separate parameter) | Proof that the intended system prompt was active at inference time | No system prompt attestation |
This is not a criticism of Anthropic. It is a statement about the boundary between provider responsibility and deployer responsibility. Anthropic ensures the model is safe to deploy. You must ensure your deployment is governed. SWT3 creates the evidence that bridges this gap.
The SWT3 Anthropic adapter wraps the Anthropic client. Every call to messages.create() is witnessed automatically. The response is untouched. Your application code does not change.
from anthropic import Anthropic
from swt3_ai import Witness
from swt3_ai.adapters.anthropic import wrap_anthropic
witness = Witness(
endpoint="https://your-instance.example.com/api/v1/witness",
api_key="axm_live_...",
tenant_id="YOUR_TENANT",
)
client = wrap_anthropic(Anthropic(), witness)
# Or: client = witness.wrap(Anthropic()) # auto-detected
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
system="You are a compliance analyst.",
messages=[{"role": "user", "content": "Review this policy document."}],
)
# response is untouched -- witnessing happens in the background
witness.flush()
import Anthropic from '@anthropic-ai/sdk';
import { Witness, wrapAnthropic } from '@tenova/swt3-ai';
const witness = new Witness({
endpoint: 'https://your-instance.example.com/api/v1/witness',
apiKey: 'axm_live_...',
tenantId: 'YOUR_TENANT',
});
const client = wrapAnthropic(new Anthropic(), witness);
// Or: const client = witness.wrap(new Anthropic()); // auto-detected
const response = await client.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
system: 'You are a compliance analyst.',
messages: [{ role: 'user', content: 'Review this policy document.' }],
});
// response is untouched -- witnessing happens in the background
await witness.flush();
model_id: The exact Claude model string returned by the API (e.g., claude-sonnet-4-20250514). Proves which model version processed this request.
prompt_hash: SHA-256 of the messages array. You can prove what was sent without storing the content itself.
response_hash: SHA-256 of the response content. The full output is fingerprinted.
system_prompt_hash: SHA-256 of the system parameter. Proves which system prompt was active at inference time.
token_usage: Input tokens, output tokens, and total. Captured from the API response metadata.
latency_ms: Wall-clock inference time. Enables performance drift detection over time.
The anchor proves the exact model version, prompt hash, and response hash for each inference. To verify a specific decision, request the anchor fingerprint and re-hash the claimed input/output. If the hashes match, the record is authentic. If they do not, the evidence has been altered.
Claude's streaming API sends response tokens incrementally, which is critical for user-facing applications. The TypeScript adapter handles both streaming patterns -- create({ stream: true }) and the .stream() convenience method -- and assembles the full response for witnessing after the stream completes.
import Anthropic from '@anthropic-ai/sdk';
import { Witness, wrapAnthropic } from '@tenova/swt3-ai';
const witness = new Witness({
endpoint: 'https://your-instance.example.com/api/v1/witness',
apiKey: 'axm_live_...',
tenantId: 'YOUR_TENANT',
});
const client = wrapAnthropic(new Anthropic(), witness);
const stream = await client.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
system: 'You are a compliance analyst.',
messages: [{ role: 'user', content: 'Summarize the key risks.' }],
stream: true,
});
for await (const event of stream) {
if (event.type === 'content_block_delta' && event.delta.type === 'text_delta') {
process.stdout.write(event.delta.text);
}
}
// Anchor minted after stream completes -- full response hash covers all chunks
await witness.flush();
const stream = client.messages.stream({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
system: 'You are a compliance analyst.',
messages: [{ role: 'user', content: 'Summarize the key risks.' }],
});
stream.on('text', (text) => process.stdout.write(text));
const finalMessage = await stream.finalMessage();
// Anchor already queued -- covers the complete assembled response
await witness.flush();
Python streaming note. The Python adapter does not yet support streaming. For streaming use cases, use the TypeScript SDK. Non-streaming Python calls (messages.create() without stream=True) are fully supported.
The response hash must cover the complete output, not individual chunks. The adapter buffers the stream internally, assembles the full response, then computes the hash. Your application receives tokens in real time. The witness anchor is minted only after the final token arrives, ensuring the fingerprint covers the entire response.
Streaming and non-streaming calls to the same model with the same input produce identical response hashes when the model output is the same. The witnessing layer is transport-agnostic. Verify this by comparing response_hash values across both call patterns in the ledger.
Anthropic's API accepts the system prompt as a separate system parameter, distinct from the messages array. This is an important design choice -- the system prompt sets the behavioral boundary for the model and should be treated as a governance artifact, not just another message.
The SWT3 adapter extracts the system parameter and hashes it independently as system_prompt_hash. This creates a continuous record of which system prompt was active at each inference. If your system prompt changes between deployments -- intentionally or accidentally -- the hash changes, and the ledger shows exactly when.
| Timestamp | Model | system_prompt_hash | Signal |
|---|---|---|---|
| 2026-10-18 09:00 | claude-sonnet-4-20250514 | a3f8c2... |
Stable |
| 2026-10-18 14:30 | claude-sonnet-4-20250514 | a3f8c2... |
Stable |
| 2026-10-19 02:15 | claude-sonnet-4-20250514 | 7e1b09... |
Drift detected |
The system prompt hash changed overnight. Either a deployment pushed a new prompt, or configuration management failed. Either way, the evidence exists.
The system_prompt_hash in each anchor creates an immutable record of prompt configuration over time. Changes are detectable without accessing the prompt content itself -- the hash is sufficient to prove whether the prompt was stable or changed.
Query the ledger for distinct system_prompt_hash values over the assessment period. Each unique hash represents a distinct system prompt version. Cross-reference hash transitions with the organization's change management records. Any hash change without a corresponding change ticket is a finding -- it means the behavioral boundary of the model changed without documented approval.
Anthropic's separate system parameter makes this possible. Because the system prompt is structurally isolated from user messages in the API, the adapter can hash it independently. Providers that embed system prompts inside the messages array make this separation harder. Anthropic's design is governance-friendly.
Anthropic's Responsible Scaling Policy (RSP) defines AI Safety Levels (ASL) and commits to specific safeguards at each level. SWT3 witnessing does not replace RSP -- it creates the deployer-side evidence that RSP's provider-side commitments are being honored in production.
| RSP Commitment | What Anthropic Does | What SWT3 Witnesses | Procedure |
|---|---|---|---|
| Capability evaluation | Tests models before release for dangerous capabilities | Records which model version was used at each inference | AI-INF.1 |
| Deployment safeguards | Applies usage restrictions based on ASL classification | Witnesses whether guardrails were active and whether they intervened | AI-GRD.1 |
| Model version tracking | Publishes model version strings (e.g., claude-sonnet-4-20250514) |
Anchors the exact version string to each inference decision | AI-INF.1 |
| Safety training (Constitutional AI) | Aligns model behavior via RLHF and Constitutional AI | Detects behavioral drift via response hash patterns over time | AI-DRIFT.1 |
| Incident response | Commits to model recall if dangerous capabilities are discovered | Provides evidence chain for revocation anchors (AI-REV.1) | AI-REV.1 |
| Third-party evaluation | Supports external red-teaming and auditing | Gives auditors independently verifiable evidence of production behavior | AI-AUDIT.1 |
RSP is the provider's safety commitment. SWT3 is the deployer's operational evidence. Together, they close the accountability loop: Anthropic proves the model is safe to deploy, and SWT3 proves your deployment is governed. For the full crosswalk mapping RSP commitments to SWT3 procedures, see the Anthropic RSP Crosswalk guide.
Every Claude inference anchor maps to specific regulatory obligations. This is not theoretical -- the anchor is the artifact that satisfies the requirement.
| Obligation | Regulation | SWT3 Evidence | Procedure |
|---|---|---|---|
| Deployer must log AI system operation | EU AI Act Art. 26 | Per-inference anchor with model ID, prompt hash, response hash, timestamp | AI-INF.1 |
| Automatic logging capabilities | EU AI Act Art. 12 | Continuous witnessing -- every call logged with cryptographic fingerprint | AI-INF.1 |
| Map AI risks in deployment context | NIST AI RMF MAP 1.5 | Model version, system prompt hash, and usage patterns per deployment | AI-INF.1, AI-INF.2 |
| Measure AI system behavior over time | NIST AI RMF MEASURE 2.2 | Drift detection via hash comparison across assessment windows | AI-DRIFT.1 |
| AI management system -- operational planning | ISO 42001 A.6.2.6 | Continuous evidence of AI system operation under management controls | AI-INF.1, AI-INF.2 |
| Model risk management -- ongoing monitoring | SR 11-7 / SR 26-2 | Per-decision evidence trail with model version pinning and behavioral fingerprints | AI-INF.1 |
| Human oversight measures | EU AI Act Art. 14 | Guardrail intervention evidence, system prompt governance records | AI-GRD.1, AI-INF.2 |
Request a ledger export filtered by model_id LIKE 'claude%' for the assessment period. For each regulatory requirement: (1) confirm anchors exist with appropriate density (no gaps exceeding the stated monitoring interval), (2) verify system_prompt_hash stability or documented changes, (3) spot-check 5 anchors by confirming the model_id matches the organization's approved model list. If the organization claims to use only claude-sonnet-4-20250514 but the ledger shows claude-3-5-haiku-20241022 anchors, there is an undocumented model in production.
# Python
pip install swt3-ai anthropic
# TypeScript
npm install @tenova/swt3-ai @anthropic-ai/sdk
# Python -- three lines added to any Claude integration
from anthropic import Anthropic
from swt3_ai import Witness
from swt3_ai.adapters.anthropic import wrap_anthropic
witness = Witness(endpoint="https://your-instance.example.com/api/v1/witness", api_key="axm_live_...", tenant_id="YOUR_TENANT")
client = wrap_anthropic(Anthropic(), witness)
# Everything below is your existing code, unchanged
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
system="You are a compliance analyst.",
messages=[{"role": "user", "content": "What are the key risks in this contract?"}],
)
print(response.content[0].text)
witness.flush()
// TypeScript -- three lines added to any Claude integration
import Anthropic from '@anthropic-ai/sdk';
import { Witness, wrapAnthropic } from '@tenova/swt3-ai';
const witness = new Witness({ endpoint: 'https://your-instance.example.com/api/v1/witness', apiKey: 'axm_live_...', tenantId: 'YOUR_TENANT' });
const client = wrapAnthropic(new Anthropic(), witness);
// Everything below is your existing code, unchanged
const response = await client.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
system: 'You are a compliance analyst.',
messages: [{ role: 'user', content: 'What are the key risks in this contract?' }],
});
console.log(response.content[0].text);
await witness.flush();
Three lines added. Zero changes to your application logic. Every Claude inference now has a cryptographic witness anchor that proves what model was used, what was asked, and what was answered -- without storing the content itself.