2025-12-01 · Authensor

AI Agent Safety for Swift and iOS Developers

SafeClaw by Authensor provides deny-by-default action gating for Swift AI agents running on macOS and iOS. Every Process() execution, FileManager operation, and URLSession.dataTask() call is checked against your YAML policy before it runs. Install SafeClaw with npx @authensor/safeclaw on your macOS development machine or server, and integrate it into your Swift agent via the local REST API.

Swift Agent Risk Surface

Swift AI agents on macOS have access to powerful system APIs:

On iOS, while sandboxed, AI agents can still make network requests to exfiltrate data or access the app's sandbox directory. SafeClaw gates all of these with 446 tests and hash-chained audit logging.

Installation

npx @authensor/safeclaw

For iOS apps, SafeClaw's sidecar runs on your backend. The iOS client communicates with your server, which proxies gate checks through SafeClaw.

Policy

version: 1
defaultAction: deny

rules:
- action: file.read
path:
glob: "/Users//Projects/agent/data/*"
decision: allow

- action: file.write
path:
glob: "/Users//Projects/agent/output/*"
decision: allow

- action: process.exec
command:
startsWith: "swift"
decision: allow

- action: process.exec
command:
startsWith: "xcodebuild"
decision: allow

- action: network.request
host:
in: ["api.openai.com", "api.anthropic.com"]
decision: allow

- action: process.exec
command:
contains: "osascript"
decision: deny # block AppleScript execution

Swift Integration

import Foundation

struct ActionRequest: Codable {
let action: String
var path: String?
var command: String?
var host: String?
var url: String?
var method: String?
}

struct GateDecision: Codable {
let allowed: Bool
let reason: String
}

class SafeClawGate {
private let endpoint: URL
private let session = URLSession.shared

init(endpoint: String = "http://localhost:9800") {
self.endpoint = URL(string: endpoint)!
}

func check(_ request: ActionRequest) async throws -> GateDecision {
var urlRequest = URLRequest(url: endpoint.appendingPathComponent("check"))
urlRequest.httpMethod = "POST"
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
urlRequest.httpBody = try JSONEncoder().encode(request)

do {
let (data, _) = try await session.data(for: urlRequest)
return try JSONDecoder().decode(GateDecision.self, from: data)
} catch {
// Fail closed
return GateDecision(allowed: false, reason: "SafeClaw unreachable")
}
}
}

Using the Gate

let gate = SafeClawGate()

// Gate a shell command (macOS only)
func safeExec(_ command: String) async throws -> String {
let decision = try await gate.check(ActionRequest(
action: "process.exec",
command: command
))
guard decision.allowed else {
throw NSError(domain: "SafeClaw", code: 403,
userInfo: [NSLocalizedDescriptionKey: decision.reason])
}

let process = Process()
let pipe = Pipe()
process.executableURL = URL(fileURLWithPath: "/bin/zsh")
process.arguments = ["-c", command]
process.standardOutput = pipe
try process.run()
process.waitUntilExit()

return String(data: pipe.fileHandleForReading.readDataToEndOfFile(),
encoding: .utf8) ?? ""
}

// Gate a file read
func safeRead(_ path: String) async throws -> String {
let decision = try await gate.check(ActionRequest(
action: "file.read",
path: path
))
guard decision.allowed else {
throw NSError(domain: "SafeClaw", code: 403,
userInfo: [NSLocalizedDescriptionKey: decision.reason])
}

return try String(contentsOfFile: path, encoding: .utf8)
}

// Gate a network request
func safeFetch(_ url: URL) async throws -> Data {
let decision = try await gate.check(ActionRequest(
action: "network.request",
host: url.host,
url: url.absoluteString,
method: "GET"
))
guard decision.allowed else {
throw NSError(domain: "SafeClaw", code: 403,
userInfo: [NSLocalizedDescriptionKey: decision.reason])
}

let (data, _) = try await URLSession.shared.data(from: url)
return data
}

SafeClaw logs every decision to a hash-chained audit trail. MIT licensed, works with Claude and OpenAI.

Cross-References

Try SafeClaw

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

$ npx @authensor/safeclaw