SidClaw

Claude Agent SDK

Govern Anthropic Claude Agent SDK tools with SidClaw policy enforcement, human approval, and tamper-evident audit trails.

Claude Agent SDK Integration

Anthropic's Claude Agent SDK lets you build agents that use tools to interact with external systems. SidClaw adds the governance layer: every tool call goes through policy evaluation, optional human approval, and tamper-evident audit logging.

Together: the Claude Agent SDK gives your agent tools. SidClaw governs what your agent is allowed to do with those tools.

Installation

npm install @sidclaw/sdk @anthropic-ai/agent-sdk

Quick start

TypeScript

import { AgentIdentityClient } from '@sidclaw/sdk';
import { governClaudeAgentTool } from '@sidclaw/sdk/claude-agent-sdk';
import { tool } from '@anthropic-ai/agent-sdk';
import { z } from 'zod';

const sidclaw = new AgentIdentityClient({
  apiKey: process.env.SIDCLAW_API_KEY!,
  apiUrl: 'https://api.sidclaw.com',
  agentId: 'my-agent',
});

// Define a Claude Agent SDK tool
const searchTool = tool('search', {
  description: 'Search the knowledge base',
  parameters: z.object({ query: z.string() }),
  execute: async ({ query }) => {
    return await searchKnowledgeBase(query);
  },
});

// Wrap it with SidClaw governance
const governedSearch = governClaudeAgentTool(sidclaw, searchTool, {
  dataClassification: 'internal',
});

// Every call now goes through SidClaw policy evaluation first
const result = await governedSearch.execute({ query: 'revenue Q4' });

Python

from sidclaw import SidClaw
from sidclaw.middleware.claude_agent_sdk import govern_claude_agent_tool, ClaudeAgentGovernanceConfig
from claude_agent_sdk import tool

sidclaw = SidClaw(api_key="ai_...", agent_id="my-agent")

@tool
def search(query: str) -> str:
    """Search the knowledge base"""
    return search_knowledge_base(query)

# Wrap with governance
config = ClaudeAgentGovernanceConfig(data_classification="internal")
governed_search = govern_claude_agent_tool(sidclaw, search, config)

# Every call now goes through SidClaw policy evaluation first
result = governed_search.execute(query="revenue Q4")

Configuration

ClaudeAgentGovernanceConfig

FieldTypeDefaultDescription
dataClassificationDataClassification"internal"Data classification for governed tools.
resourceScopestring"claude_agent"Resource scope sent to the policy engine.
targetIntegrationstringtool nameOverride the target integration name. Defaults to the tool's name.
waitForApprovalbooleantrueWhether to poll for human approval when decision is approval_required.
approvalTimeoutMsnumber300000 (5 min)Timeout in ms when waiting for approval.
approvalPollIntervalMsnumber2000Polling interval in ms for approval status.

Python config

FieldTypeDefaultDescription
data_classificationstr"internal"Data classification for governed tools.
resource_scopestr"claude_agent"Resource scope sent to the policy engine.
target_integrationstr | NoneNone (tool name)Override the target integration name.
wait_for_approvalboolTrueWhether to poll for human approval.
approval_timeout_secondsfloat300.0Timeout in seconds when waiting for approval.
approval_poll_interval_secondsfloat2.0Polling interval in seconds for approval status.

Patterns

Pattern 1: Single tool governance

Wrap individual tools with governance.

import { governClaudeAgentTool } from '@sidclaw/sdk/claude-agent-sdk';

const governedTool = governClaudeAgentTool(sidclaw, myTool, {
  dataClassification: 'confidential',
  resourceScope: 'production',
});

const result = await governedTool.execute({ input: 'data' });
from sidclaw.middleware.claude_agent_sdk import govern_claude_agent_tool, ClaudeAgentGovernanceConfig

config = ClaudeAgentGovernanceConfig(
    data_classification="confidential",
    resource_scope="production",
)
governed = govern_claude_agent_tool(client, my_tool, config)
result = governed.execute(input="data")

Pattern 2: Batch tool governance

Wrap all tools at once. Each tool's name is used as the target integration.

import { governClaudeAgentTools } from '@sidclaw/sdk/claude-agent-sdk';

const governedTools = governClaudeAgentTools(sidclaw, [searchTool, writeTool, deleteTool], {
  dataClassification: 'confidential',
});

// Use governed tools with your Claude agent
from sidclaw.middleware.claude_agent_sdk import govern_claude_agent_tools

governed = govern_claude_agent_tools(client, [search_tool, write_tool, delete_tool])

Pattern 3: Approval workflow

When a policy requires human approval, the middleware can wait for the decision.

const governedTool = governClaudeAgentTool(sidclaw, deployTool, {
  waitForApproval: true,
  approvalTimeoutMs: 600_000,     // Wait up to 10 minutes
  approvalPollIntervalMs: 3_000,  // Check every 3 seconds
  dataClassification: 'restricted',
});

try {
  // If approval_required, this will wait until a human approves/denies
  const result = await governedTool.execute({ environment: 'production' });
} catch (error) {
  if (error instanceof ActionDeniedError) {
    console.log('Action was denied:', error.reason);
  }
}
from sidclaw.middleware.claude_agent_sdk import govern_claude_agent_tool, ClaudeAgentGovernanceConfig
from sidclaw import ActionDeniedError

config = ClaudeAgentGovernanceConfig(
    wait_for_approval=True,
    approval_timeout_seconds=600,
    approval_poll_interval_seconds=3,
    data_classification="restricted",
)

governed = govern_claude_agent_tool(client, deploy_tool, config)

try:
    result = governed.execute(environment="production")
except ActionDeniedError as e:
    print(f"Action was denied: {e.reason}")

Policy examples

Allow all search operations

{
  "name": "Allow search tools",
  "target_integration": "search",
  "operation": "*",
  "resource_scope": "*",
  "data_classification_max": "internal",
  "effect": "allow",
  "priority": 10
}

Require approval for write operations

{
  "name": "Approve write operations",
  "target_integration": "write",
  "operation": "*",
  "resource_scope": "*",
  "data_classification_max": "confidential",
  "effect": "approval_required",
  "priority": 20
}

Deny production deployments

{
  "name": "Block production deploy (restricted data)",
  "target_integration": "deploy",
  "operation": "*",
  "resource_scope": "production",
  "data_classification_max": "restricted",
  "effect": "deny",
  "priority": 30
}

API reference

TypeScript

governClaudeAgentTool(client, tool, config?)

Wraps a single Claude Agent SDK tool with SidClaw governance.

Parameters:

ParameterTypeDescription
clientAgentIdentityClientConfigured SidClaw client.
toolClaudeAgentToolLikeClaude Agent SDK tool (duck-typed: must have name and execute).
configClaudeAgentGovernanceConfigOptional governance configuration.

Returns: A governed tool with the same shape as the input (name, description, parameters preserved).

governClaudeAgentTools(client, tools, config?)

Wraps all tools in an array with SidClaw governance. Uses each tool's name as targetIntegration.

Parameters:

ParameterTypeDescription
clientAgentIdentityClientConfigured SidClaw client.
toolsClaudeAgentToolLike[]Array of Claude Agent SDK tools.
configOmit<ClaudeAgentGovernanceConfig, 'targetIntegration'>Optional governance configuration (without targetIntegration).

Returns: Array of governed tools.

Python

govern_claude_agent_tool(client, tool, config?)

Wraps a sync Claude Agent SDK tool with SidClaw governance.

Parameters:

ParameterTypeDescription
clientSidClawSync SidClaw client.
toolAnyClaude Agent SDK tool (duck-typed: must have name and execute).
configClaudeAgentGovernanceConfigOptional governance configuration.

Returns: GovernedClaudeAgentTool — a governed wrapper preserving name, description, parameters.

govern_claude_agent_tool_async(client, tool, config?)

Wraps an async Claude Agent SDK tool with SidClaw governance.

govern_claude_agent_tools(client, tools, config?)

Wraps all tools in a sequence with SidClaw governance (sync).

govern_claude_agent_tools_async(client, tools, config?)

Wraps all tools in a sequence with SidClaw governance (async).

Error handling

import { ActionDeniedError, ApprovalTimeoutError } from '@sidclaw/sdk';

try {
  const result = await governedTool.execute({ query: 'sensitive data' });
} catch (error) {
  if (error instanceof ActionDeniedError) {
    console.log('Policy denied:', error.reason);
    console.log('Trace:', error.traceId);
  } else if (error instanceof ApprovalTimeoutError) {
    console.log('Approval timed out');
  }
}
from sidclaw import ActionDeniedError, ApprovalTimeoutError

try:
    result = governed_tool.execute(query="sensitive data")
except ActionDeniedError as e:
    print(f"Policy denied: {e.reason}, trace: {e.trace_id}")
except ApprovalTimeoutError as e:
    print(f"Approval timed out after {e.timeout}s")