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
- Any programming language with HTTP client support
- Node.js 18+ (for the SafeClaw runtime, or use the HTTP API directly)
- A SafeClaw account at safeclaw.onrender.com (free tier, 7-day renewable keys, no credit card)
- SafeClaw API key from the browser dashboard
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
- SafeClaw Action Types Reference
- SafeClaw Policy Configuration Reference
- Glossary: Deny-by-Default Architecture
- FAQ: What Languages Does SafeClaw Support?
- Use Case: Custom Agent with Full SafeClaw Coverage
Try SafeClaw
Action-level gating for AI agents. Set it up in your browser in 60 seconds.
$ npx @authensor/safeclaw