Claude agent
A Claude tool-use loop with ProofLedger woven through it: the run is traced, every tool_use block is logged as a signed event, and risky tools are policy-checked before execution.
TypeScript
import Anthropic from "@anthropic-ai/sdk";
import { ProofLedger, PolicyBlockedError } from "@proofledger/sdk";
ProofLedger.enable({
apiKey: process.env.PROOFLEDGER_API_KEY,
agentName: "claude-support-agent",
owner: "support",
framework: "claude-code",
model: "claude-opus-4-8",
policyMode: "enforce",
});
await ProofLedger.registerAgent();
const anthropic = new Anthropic();
const workflowId = "wf_ticket_4821";
await ProofLedger.logWorkflowStep({
workflowId, eventType: "task_received",
action: "Resolve ticket #4821",
});
let messages = [{ role: "user" as const, content: "Refund order ORD-123" }];
for (;;) {
const response = await anthropic.messages.create({
model: "claude-opus-4-8",
max_tokens: 1024,
tools: TOOLS,
messages,
});
const toolUse = response.content.find((b) => b.type === "tool_use");
if (!toolUse) break; // final answer
// Every tool call goes through ProofLedger BEFORE it runs.
// In enforce mode a blocked tool throws — the loop reports and stops.
try {
await ProofLedger.logToolCall({
workflowId,
toolName: toolUse.name,
inputSummary: JSON.stringify(toolUse.input).slice(0, 500),
sensitiveAction: toolUse.name === "issue_refund",
});
} catch (err) {
if (err instanceof PolicyBlockedError) {
await ProofLedger.logWorkflowStep({
workflowId, status: "failed",
action: `Stopped: ${err.evaluation.reason}`,
});
throw err;
}
throw err;
}
const result = await runTool(toolUse.name, toolUse.input);
messages = [
...messages,
{ role: "assistant" as const, content: response.content },
{
role: "user" as const,
content: [{ type: "tool_result" as const, tool_use_id: toolUse.id,
content: JSON.stringify(result) }],
},
];
}
await ProofLedger.logWorkflowStep({
workflowId, status: "completed", action: "Ticket resolved",
});
await ProofLedger.flush();Note
sensitiveAction: true on the refund tool routes it through require_approval — in enforce mode the loop pauses right there until a human approves it in the dashboard.