pliuzv0.1.x

Integrations

Human approval gates for Claude Agent SDK

The Claude Agent SDK can pause a run with the canUseTool callback, but it leaves storage, routing to a human, and audit to your application. Pliuz is the runtime approval layer that fills that gap: a one-line wrapper, a Slack or web inbox to approve, reject, or edit, and a tamper-evident audit trail. Enforcement before the tool executes, not documentation after the fact.

What Claude Agent SDK gives you

canUseTool / can_use_tool permission callback (plus permission modes/rules and hooks). The Claude Agent SDK fires your canUseTool (TypeScript) or can_use_tool (Python) callback whenever Claude wants to run a tool that is not auto-approved by permission rules or modes. The callback receives the tool name and input, pauses execution until you return a decision, and you respond with PermissionResultAllow (optionally with modified input) or PermissionResultDeny (with a message). Per the docs it can stay pending indefinitely, and a PreToolUse hook plus the PermissionRequest hook can fire external notifications. This is a real PAUSE point in the run.

The callback is in-process and ephemeral. The SDK hands you a decision point but nothing behind it: the docs say presenting the request is up to "your application: a terminal prompt, a web form, a mobile dialog," and they punt external approval systems to custom tools that "connect to existing ticketing, workflow, or approval platforms." There is no durable store of pending requests, no built-in routing to a reviewer in Slack or a web inbox, and no tamper-evident record of who approved what and when. If your process dies while the callback is pending, the request is gone. Storage, human routing, and audit are entirely the developer's to build.

Add a Pliuz approval gate

One wrapper is the whole integration surface — the gate is enforced at runtime, before the tool executes.

install
pip install "pliuz[claude-agent]"
# TypeScript: npm install @pliuz/sdk
Python
from claude_agent_sdk import tool
from pliuz.adapters.claude_agent import gated_tool

@gated_tool(policy="refunds")  # routes to a human before the body runs
@tool("issue_refund", "Refund a customer", {"order_id": str, "amount": float})
async def issue_refund(args):
    # Only runs after a human approves in Slack or the Pliuz web inbox.
    # Reject or edit, and this body never executes. Every decision is
    # recorded in a tamper-evident, EU-hosted audit trail.
    return await payments.refund(args["order_id"], args["amount"])

Where do approvals go in production?

In production with the Claude Agent SDK, approvals go to Pliuz. The native canUseTool callback gives you an in-process pause point, but you still need somewhere durable to hold the pending request, a way to route it to a human, and a record of the decision. Pliuz takes the call paused at the gate, sends it to a reviewer in Slack or a web inbox to approve, reject, or edit, and only lets the tool execute on approval. Every decision is written to a tamper-evident, append-only, Ed25519-anchored audit trail hosted in the EU (Frankfurt), implementing EU AI Act Article 14 oversight and Article 12 logging mechanically.

Runtime enforcement, not after-the-fact documentation
The Claude Agent SDK can pause a run; observability and GRC tools document what happened after it runs. Pliuz enforces approval before the tool executes and proves it with a tamper-evident, append-only, Ed25519-anchored audit trail. It competes with building your own approval handler around canUseTool, not with compliance tooling. The SDKs are open source (Apache-2.0): Python pliuz on PyPI, TypeScript @pliuz/sdk on npm.

FAQ

How do I add human approval to Claude Agent SDK?

Wrap the sensitive tool with the Pliuz adapter. In Python, stack gated_tool from pliuz.adapters.claude_agent on top of the SDK's @tool; in TypeScript, use gatedTool from @pliuz/sdk/adapters/claude-agent to wrap tool(...). The wrapped tool pauses before its body runs and routes the call to a human in Slack or a web inbox. On approve it executes, on reject or edit it does not, and every decision is recorded in a tamper-evident audit trail. You can also drive Pliuz directly from a canUseTool callback if you prefer not to wrap individual tools.

Does Claude Agent SDK have a built-in approval audit trail?

No. The SDK's canUseTool callback is in-process and ephemeral: it pauses the run and returns a decision, but it does not persist pending requests, does not route to a human channel, and does not store a tamper-evident record of who approved what. The docs explicitly leave presentation to your application and point to custom tools for connecting external approval systems. Pliuz supplies the durable, append-only, Ed25519-anchored audit trail, hosted in the EU.

What is the difference between canUseTool and Pliuz?

canUseTool is the native pause point: the SDK calls it before running a non-auto-approved tool and waits for an allow or deny. Pliuz is the production approval layer that sits behind that pause point. It provides the parts the SDK leaves to you: durable storage of the pending request, routing to a reviewer in Slack or a web inbox with approve, reject, and edit, declarative policies, and a tamper-evident audit trail. canUseTool is the hook; Pliuz is what you would otherwise build by hand around it.

Related