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:
Process(formerlyNSTask) — execute shell commandsFileManager— read, write, move, delete files and directoriesURLSession— make network requests to any hostNSAppleScript— execute AppleScript for system automation
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
- Deny-by-Default Explained
- Serverless Functions Integration
- Hash-Chained Audit Logs
- Zero Trust Agent Architecture
Try SafeClaw
Action-level gating for AI agents. Set it up in your browser in 60 seconds.
$ npx @authensor/safeclaw