2026-01-16 · Authensor

Integrating SafeClaw with Any Custom Agent Framework

SafeClaw is action-level gating for AI agents, built by Authensor. It works with any agent framework — not just LangChain, CrewAI, or AutoGen. This guide covers the universal integration pattern for adding SafeClaw policy enforcement to a custom agent built in TypeScript, Python, Go, or any language that can make HTTP calls.

Prerequisites

Step-by-Step Instructions

Step 1: Install SafeClaw

npx @authensor/safeclaw

Complete the browser-based setup wizard. SafeClaw has zero third-party dependencies, is validated by 446 tests, and runs in TypeScript strict mode. The client is 100% open source under the MIT license.

Step 2: Understand the Action Model

SafeClaw evaluates four action types:

| Action Type | Description | Examples |
| ------------ | ---------------------------------- | --------------------------------- |
| file_read | Reading files from disk | Config files, data files, secrets |
| file_write | Writing or modifying files | Code generation, log writing |
| shell_exec | Executing shell commands | Build commands, scripts, tools |
| network | Making HTTP/network requests | API calls, webhooks, downloads |

Every action has a target string (file path, command, or URL). SafeClaw matches the target against policy rules and returns ALLOW, DENY, or REQUIRE_APPROVAL.

Step 3: Integrate Using the TypeScript Client

import { SafeClaw } from "@authensor/safeclaw";

const safeclaw = new SafeClaw({
apiKey: process.env.SAFECLAW_API_KEY!,
agentId: "custom-agent",
mode: "enforce", // "simulate" for testing
});

async function executeAction(
actionType: "file_read" | "file_write" | "shell_exec" | "network",
target: string,
executeFn: () => Promise<unknown>
): Promise<{ success: boolean; result?: unknown; blocked?: string }> {
const evaluation = await safeclaw.evaluate({
actionType,
target,
metadata: {
agent: "custom-agent",
timestamp: new Date().toISOString(),
},
});

if (evaluation.decision === "DENY") {
return { success: false, blocked: DENY: ${evaluation.reason} };
}

if (evaluation.decision === "REQUIRE_APPROVAL") {
return { success: false, blocked: REQUIRE_APPROVAL: ${evaluation.reason} };
}

const result = await executeFn();
return { success: true, result };
}

Step 4: Integrate Using the HTTP API (Any Language)

If your agent is not written in TypeScript, use the SafeClaw HTTP evaluation endpoint directly.

Python:

import requests
import os

SAFECLAW_API_KEY = os.environ["SAFECLAW_API_KEY"]
SAFECLAW_URL = "https://safeclaw.onrender.com/api/evaluate"

def check_action(action_type: str, target: str, agent_id: str = "custom-agent") -> dict:
response = requests.post(
SAFECLAW_URL,
headers={
"Authorization": f"Bearer {SAFECLAW_API_KEY}",
"Content-Type": "application/json",
},
json={
"actionType": action_type,
"target": target,
"agentId": agent_id,
"metadata": {"agent": agent_id},
},
)
return response.json()

Usage

result = check_action("file_write", "./output/report.md") if result["decision"] == "ALLOW": with open("./output/report.md", "w") as f: f.write("Report content")

Go:

package main

import (
"bytes"
"encoding/json"
"net/http"
"os"
)

type EvalRequest struct {
ActionType string json:"actionType"
Target string json:"target"
AgentID string json:"agentId"
Metadata map[string]string json:"metadata"
}

type EvalResponse struct {
Decision string json:"decision"
Rule string json:"rule"
Reason string json:"reason"
EvaluationTime string json:"evaluationTime"
}

func checkAction(actionType, target string) (*EvalResponse, error) {
body, _ := json.Marshal(EvalRequest{
ActionType: actionType,
Target: target,
AgentID: "custom-agent",
Metadata: map[string]string{"agent": "custom-agent"},
})

req, _ := http.NewRequest("POST", "https://safeclaw.onrender.com/api/evaluate", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("SAFECLAW_API_KEY"))
req.Header.Set("Content-Type", "application/json")

resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()

var result EvalResponse
json.NewDecoder(resp.Body).Decode(&result)
return &result, nil
}

cURL (testing/debugging):

curl -X POST https://safeclaw.onrender.com/api/evaluate \
  -H "Authorization: Bearer $SAFECLAW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "actionType": "shell_exec",
    "target": "npm test",
    "agentId": "custom-agent",
    "metadata": {"agent": "custom-agent"}
  }'

Step 5: Implement the Agent Loop Pattern

The standard integration pattern wraps every tool/action call:

class SafeClawAgent {
  private safeclaw: SafeClaw;

constructor() {
this.safeclaw = new SafeClaw({
apiKey: process.env.SAFECLAW_API_KEY!,
agentId: "custom-agent",
mode: "enforce",
});
}

async readFile(path: string): Promise<string> {
await this.gate("file_read", path);
const fs = await import("node:fs/promises");
return fs.readFile(path, "utf-8");
}

async writeFile(path: string, content: string): Promise<void> {
await this.gate("file_write", path);
const fs = await import("node:fs/promises");
await fs.writeFile(path, content);
}

async exec(command: string): Promise<string> {
await this.gate("shell_exec", command);
const { execSync } = await import("node:child_process");
return execSync(command, { encoding: "utf-8" });
}

async fetch(url: string): Promise<Response> {
await this.gate("network", url);
return globalThis.fetch(url);
}

private async gate(actionType: string, target: string): Promise<void> {
const result = await this.safeclaw.evaluate({
actionType,
target,
metadata: { agent: "custom-agent" },
});

if (result.decision !== "ALLOW") {
throw new Error(
SafeClaw ${result.decision}: ${target} — ${result.reason}
);
}
}
}

Step 6: Test in Simulation Mode

Set mode: "simulate". All evaluations are logged to the tamper-proof audit trail (SHA-256 hash chain) without blocking actions. Review at safeclaw.onrender.com.

Step 7: Switch to Enforce Mode

Set mode: "enforce" after validating. SafeClaw evaluates each action in sub-millisecond time.

Example Policy

# safeclaw.config.yaml
version: "1.0"
agent: custom-agent
defaultAction: deny

rules:
- id: allow-read-data
action: file_read
target: "./data/**"
decision: allow

- id: allow-read-config
action: file_read
target: "./config/**"
decision: allow

- id: deny-read-secrets
action: file_read
target: "*/.env"
decision: deny

- id: deny-read-keys
action: file_read
target: "*/key*"
decision: deny

- id: allow-write-output
action: file_write
target: "./output/**"
decision: allow

- id: gate-shell
action: shell_exec
target: "*"
decision: require_approval

- id: allow-internal-api
action: network
target: "https://internal.api.company.com/**"
decision: allow

- id: deny-external
action: network
target: "*"
decision: deny

Example Action Requests

1. ALLOW — Reading data file:

{
  "actionType": "file_read",
  "target": "./data/users.json",
  "agentId": "custom-agent",
  "decision": "ALLOW",
  "rule": "allow-read-data",
  "evaluationTime": "0.3ms"
}

2. DENY — Reading secrets:

{
  "actionType": "file_read",
  "target": "./.env.production",
  "agentId": "custom-agent",
  "decision": "DENY",
  "rule": "deny-read-secrets",
  "evaluationTime": "0.2ms"
}

3. ALLOW — Writing to output:

{
  "actionType": "file_write",
  "target": "./output/analysis.json",
  "agentId": "custom-agent",
  "decision": "ALLOW",
  "rule": "allow-write-output",
  "evaluationTime": "0.3ms"
}

4. REQUIRE_APPROVAL — Shell command:

{
  "actionType": "shell_exec",
  "target": "psql -c 'SELECT * FROM users'",
  "agentId": "custom-agent",
  "decision": "REQUIRE_APPROVAL",
  "rule": "gate-shell",
  "evaluationTime": "0.4ms"
}

5. DENY — External network request:

{
  "actionType": "network",
  "target": "https://pastebin.com/raw/abc123",
  "agentId": "custom-agent",
  "decision": "DENY",
  "rule": "deny-external",
  "evaluationTime": "0.2ms"
}

Troubleshooting

Issue 1: HTTP API returns 403 Forbidden

Symptom: The evaluate endpoint returns 403 instead of a decision.

Fix: Verify the Authorization header uses the Bearer prefix. Ensure the API key is active. Free tier keys expire after 7 days and must be renewed at safeclaw.onrender.com. The control plane sees only action metadata, never your keys or data.

Issue 2: Evaluation results are inconsistent between local and HTTP

Symptom: TypeScript client and HTTP API return different decisions for the same action.

Fix: Ensure both use the same agentId. Policy rules are matched per-agent. Verify the safeclaw.config.yaml referenced by the TypeScript client matches the policy configured in the dashboard for HTTP API evaluations.

Issue 3: Custom action types not recognized

Symptom: SafeClaw returns an error for action types like database_query or email_send.

Fix: SafeClaw supports four action types: file_read, file_write, shell_exec, network. Map custom action types to the closest SafeClaw type. Database queries map to network. Email sending maps to network. File downloads map to network.

Cross-References

Try SafeClaw

Action-level gating for AI agents. Set it up in your browser in 60 seconds.

$ npx @authensor/safeclaw