Advanced Patterns

July 20, 2026 ยท View on GitHub

Custom Tools

struct UppercaseTool: ToolDefinition {
    let name = "uppercase"
    let description = "Convert text to uppercase."
    let annotations = ToolAnnotations(readOnlyHint: true, idempotentHint: true)
    let parameters: [String: AnyCodable] = [:]

    func execute(params: [String: AnyCodable]) async throws -> ToolResult {
        let text = params["text"]?.value as? String ?? ""
        return .success(data: text.uppercased())
    }
}

Hooks

let hooks = HookManager()
Runner.setHookManager(hooks)

Use hooks to observe or gate tool execution in host applications.

Skills and MCP discovery

Use the high-level macOS facade for typed CLI discovery and installation:

let sdk = AutohandSDK(configuration: .init(cwd: projectPath))
try sdk.start()
defer { sdk.close() }

let registry = try await sdk.getSkillsRegistry()
let filesystemTools = try await sdk.listMCPTools(.init(serverName: "filesystem"))

if registry.skills.contains(where: { \$0.id == "release-readiness" }) {
    let result = try await sdk.installSkill(.init(
        skillName: "release-readiness",
        scope: .project
    ))
    print(result.path ?? "installed")
}

Call sdk.client when an application also needs lower-level goal, autoresearch, or prompt RPCs.

Structured JSON

Use Codable validation in the host:

struct ReleaseRisk: Codable {
    let summary: String
    let risks: [String]
}

let text = try await Runner.runSync(agent: agent, prompt: "Return release risk as JSON")
let risk = try JSONDecoder().decode(ReleaseRisk.self, from: Data(text.utf8))

Sessions And Loop Strategies

Choose .react for simple tasks, .planAndExecute for larger implementation work, .parallel for independent actions, and .reflexion when the agent should critique its own output between turns. Runtime options override strategy prompt defaults. They are model guidance; tool calls returned by the model are currently executed serially:

let result = try await Runner.run(
    agent: planner,
    prompt: "Plan and implement the change",
    options: .init(maxPlanningSteps: 3)
)