Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/jasonkneen/openclicky/llms.txt

Use this file to discover all available pages before exploring further.

This page documents every public type and method declared in cursor-buddy/OpenClickySDK.swift. These are the only types your host app needs to interact with directly.

OpenClickySDKMode

public enum OpenClickySDKMode: Equatable
Controls how the OpenClicky runtime behaves when started. Pass this to OpenClickySDKSession.init(mode:).

Cases

menuBar
case
Keep the existing menu-bar runtime. Use this if you want CompanionManager to behave exactly as the default OpenClicky app — with the global push-to-talk monitor, overlay auto-show, and onboarding tied to menu-bar state.
embeddedWindow
case
Run OpenClicky in an in-window runtime suitable for SDK embedding. In this mode the global push-to-talk shortcut monitor is not started, the cursor overlay does not auto-show, and onboarding is not tied to menu-bar state. This is the recommended mode for SDK hosts.

OpenClickySDKPanelActions

public struct OpenClickySDKPanelActions
A struct of seven callback closures that let your host app respond to control affordances inside the embedded OpenClickySDKPanel. All callbacks default to no-ops — only wire the ones your app needs to handle.

Initializer

public init(
    onPanelDismiss: @escaping () -> Void = {},
    onQuit: @escaping () -> Void = {},
    onOpenHUD: @escaping () -> Void = {},
    onOpenMemory: @escaping () -> Void = {},
    onOpenVisual: @escaping () -> Void = {},
    onOpenFeedback: @escaping () -> Void = {},
    onShowSettings: @escaping () -> Void = {}
)

Callbacks

onPanelDismiss
() -> Void
Called when the close affordance in the panel UI is activated. Use this to set your presentation binding to false or close your host window.
onPanelDismiss: { showOpenClicky = false }
onQuit
() -> Void
Called when the user taps the “Quit OpenClicky” action inside the panel. In an embedded context this usually has the same effect as onPanelDismiss — dismiss the panel rather than terminate your host app.
onQuit: { showOpenClicky = false }
onOpenHUD
() -> Void
Opens the OpenClicky HUD surface in the host environment. Route this to whichever surface in your app displays the agent session list or Codex HUD.
onOpenHUD: { showAgentHUD = true }
onOpenMemory
() -> Void
Opens the OpenClicky memory window in the host environment. Route this to your memory/knowledge viewer.
onOpenMemory: { showMemoryWindow = true }
onOpenVisual
() -> Void
Opens the OpenClicky visual intelligence workspace in the host environment. Route this to your visual analysis surface or camera workspace.
onOpenVisual: { showVisualWorkspace = true }
onOpenFeedback
() -> Void
Opens the OpenClicky feedback / inbox link. Route this to your preferred feedback URL or form.
onOpenFeedback: {
    NSWorkspace.shared.open(URL(string: "https://your-feedback-url.com")!)
}
onShowSettings
() -> Void
Opens the settings surface in the host environment. Route this to your app’s settings window or sheet.
onShowSettings: { showSettings = true }

OpenClickySDKSession

@MainActor
public final class OpenClickySDKSession: ObservableObject
The main SDK entry point. A small host-facing session wrapper that starts and configures a self-contained OpenClicky runtime for app embedding. Conforms to ObservableObject so it can be used directly with @StateObject or @ObservedObject in SwiftUI. All methods and properties must be accessed on the main actor.

Initializer

public init(mode: OpenClickySDKMode = .embeddedWindow)
mode
OpenClickySDKMode
default:".embeddedWindow"
The execution mode for this session. Use .embeddedWindow for SwiftUI integrations where you want a local, app-owned OpenClicky surface. Use .menuBar only if you want the exact menu-bar companion behavior.
@StateObject private var sdk = OpenClickySDKSession(mode: .embeddedWindow)

Published Properties

isStarted
Bool
required
@Publishedtrue after start() succeeds, false after stop(). Observe this in SwiftUI or via Combine to react to runtime lifecycle changes.
@Published public private(set) var isStarted = false

Lifecycle

start()
func
Starts the OpenClicky runtime. Loads the bundled knowledge index, refreshes all permissions, warms TTS clients, and shows the cursor overlay if permitted. Safe to call multiple times — exits immediately if already started.Call this in .onAppear or from your scene’s onAppear modifier.
.onAppear {
    sdk.start()
}
stop()
func
Stops the OpenClicky runtime. Cancels all in-flight voice responses, TTS playback, agent sessions, and external control servers. Safe to call multiple times — exits immediately if already stopped.Call this in .onDisappear or on app termination.
.onDisappear {
    sdk.stop()
}
restart()
func
Convenience method that calls stop() followed by start(). Useful for re-initializing the runtime after configuration changes.
sdk.restart()

Prompt and Voice Entry Points

submitTextPrompt(_:)
func
Submit a raw text prompt through the standard text-mode voice response path. The prompt is routed through the same pipeline as a push-to-talk voice transcript — it may open apps, trigger computer use, start agent tasks, or generate a Claude response depending on the content.
public func submitTextPrompt(_ prompt: String)
prompt
String
required
The text prompt to submit. Leading and trailing whitespace is trimmed internally.
sdk.submitTextPrompt("Summarize this page")
submitAgentPrompt(_:)
func
Submit a prompt directly into Agent Mode from a panel or HUD-like input. Unlike submitTextPrompt, this bypasses voice routing and goes straight to the active Codex agent session.
public func submitAgentPrompt(_ prompt: String)
prompt
String
required
The agent instruction to submit.
sdk.submitAgentPrompt("Create a bug report from these logs")
startVoiceCapture()
func
Begin microphone voice capture for follow-up input. This triggers the same dictation pipeline as pushing the microphone button in the panel. Use this to implement a custom push-to-talk button in your host app.
public func startVoiceCapture()
// Custom PTT button
Button("Hold to Talk") { sdk.startVoiceCapture() }
    .simultaneousGesture(
        DragGesture(minimumDistance: 0)
            .onEnded { _ in sdk.stopVoiceCapture() }
    )
stopVoiceCapture()
func
End microphone voice capture early. The dictation pipeline will finalize the current transcript and submit it. Call this when your custom PTT button is released.
public func stopVoiceCapture()

API Key Configuration

All key setters update OpenClicky’s internal configuration and persist the keys the same way the native app does. You do not need to restart the session after setting keys.
setAnthropicAPIKey(_:)
func
Set the Anthropic API key used for Claude voice responses and Claude-powered computer use. Persisted to UserDefaults under OpenClicky’s key namespace.
public func setAnthropicAPIKey(_ key: String)
key
String
required
The Anthropic API key (sk-ant-...). Pass an empty string to clear.
sdk.setAnthropicAPIKey("sk-ant-api03-...")
setCodexAgentAPIKey(_:)
func
Set the Codex / OpenAI-compatible API key used for agent mode and OpenAI voice responses. OpenClicky routes this through the same API client path as the OpenAI key.
public func setCodexAgentAPIKey(_ key: String)
key
String
required
The Codex or OpenAI API key. Pass an empty string to clear.
sdk.setCodexAgentAPIKey("sk-...")
setElevenLabsAPIKey(_:)
func
Set the ElevenLabs API key used for ElevenLabs TTS voice playback.
public func setElevenLabsAPIKey(_ key: String)
key
String
required
The ElevenLabs API key. Pass an empty string to clear.
sdk.setElevenLabsAPIKey("...")
setCartesiaAPIKey(_:)
func
Set the Cartesia API key used for Cartesia TTS voice playback.
public func setCartesiaAPIKey(_ key: String)
key
String
required
The Cartesia API key. Pass an empty string to clear.
sdk.setCartesiaAPIKey("...")

Panel Construction

makePanelView(isPanelPinned:actions:setPanelPinned:)
func
Build an embedded panel view pre-wired to this session. Returns an OpenClickySDKPanel — a SwiftUI View you can embed in a .sheet, NSHostingView, or any SwiftUI container.This is the primary overload. Use it when you want to handle all seven panel callbacks.
public func makePanelView(
    isPanelPinned: Bool = false,
    actions: OpenClickySDKPanelActions,
    setPanelPinned: @escaping (Bool) -> Void = { _ in }
) -> OpenClickySDKPanel
isPanelPinned
Bool
default:"false"
The initial pinned state of the panel. When true, the panel renders in a pinned/docked layout. Pass your app’s pinned state binding here.
actions
OpenClickySDKPanelActions
required
The callbacks struct controlling how panel affordances route into your host app. See OpenClickySDKPanelActions above.
setPanelPinned
(Bool) -> Void
default:"{ _ in }"
Called whenever the panel’s pin state changes. Use this to sync the pin state back into your host app’s state.
sdk.makePanelView(
    isPanelPinned: isPanelPinned,
    actions: .init(
        onPanelDismiss: { showOpenClicky = false },
        onQuit:         { showOpenClicky = false },
        onOpenHUD:      { /* your HUD */ },
        onOpenMemory:   { /* your memory UI */ },
        onOpenFeedback: { /* your feedback URL */ },
        onShowSettings: { /* your settings */ }
    ),
    setPanelPinned: { pinned in isPanelPinned = pinned }
)
.frame(minWidth: 356, minHeight: 720)
makePanelView(isPanelPinned:setPanelPinned:)
func
Convenience overload of makePanelView that uses OpenClickySDKPanelActions() with all no-op defaults. Use this when you don’t need to handle panel callbacks.
public func makePanelView(
    isPanelPinned: Bool = false,
    setPanelPinned: @escaping (Bool) -> Void = { _ in }
) -> OpenClickySDKPanel
sdk.makePanelView()
    .frame(minWidth: 356, minHeight: 720)

OpenClickySDKPanel

public struct OpenClickySDKPanel: View
A lightweight SwiftUI View wrapping CompanionPanelView that is safe to embed inside any host NSWindow, NSPanel, or SwiftUI .sheet. You do not construct this type directly — obtain it from OpenClickySDKSession.makePanelView(...).

Usage

OpenClickySDKPanel conforms to View and can be used anywhere a SwiftUI view is accepted:
// Inside a .sheet
.sheet(isPresented: $showOpenClicky) {
    sdk.makePanelView(
        isPanelPinned: false,
        actions: .init(onPanelDismiss: { showOpenClicky = false }),
        setPanelPinned: { _ in }
    )
    .frame(minWidth: 356, minHeight: 720)
    .padding(8)
}
// Inside an NSHostingView (AppKit)
let panelView = sdk.makePanelView(
    actions: .init(onPanelDismiss: { hostWindow.close() })
)
let hostingView = NSHostingView(rootView: panelView)
hostingView.frame = NSRect(x: 0, y: 0, width: 356, height: 720)
The panel renders correctly at a minimum width of 356 pt and a minimum height of 720 pt. Constraining the frame smaller than this will cause layout clipping in the conversation UI.
.frame(minWidth: 356, minHeight: 720)
The panel adapts to larger frames and supports resizing. If you want the panel to fill a window, omit the min/max constraints and let SwiftUI expand it.

Panel State

OpenClickySDKPanel observes CompanionManager (the internal state object owned by OpenClickySDKSession) and re-renders reactively as voice state, agent status, and conversation entries change. You do not need to manage any panel-internal state in your host app.

Full Example

import SwiftUI

@main
struct MyApp: App {
    @StateObject private var openClickyRuntime = OpenClickyHostRuntime()

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(openClickyRuntime)
                .onAppear { openClickyRuntime.start() }
                .onDisappear { openClickyRuntime.stop() }
        }
    }
}

@MainActor
final class OpenClickyHostRuntime: ObservableObject {
    let sdk = OpenClickySDKSession(mode: .embeddedWindow)
    @Published var isPanelPresented = false
    @Published var isPanelPinned = false

    func start() {
        sdk.start()
        sdk.setAnthropicAPIKey("sk-ant-...")
    }

    func stop() { sdk.stop() }

    func makePanel(onDismiss: @escaping () -> Void) -> some View {
        sdk.makePanelView(
            isPanelPinned: isPanelPinned,
            actions: .init(
                onPanelDismiss: onDismiss,
                onQuit: onDismiss,
                onShowSettings: { /* open settings */ }
            ),
            setPanelPinned: { [weak self] pinned in
                self?.isPanelPinned = pinned
            }
        )
    }
}

struct ContentView: View {
    @EnvironmentObject private var runtime: OpenClickyHostRuntime

    var body: some View {
        Button("Open OpenClicky") { runtime.isPanelPresented = true }
            .sheet(isPresented: $runtime.isPanelPresented) {
                runtime.makePanel { runtime.isPanelPresented = false }
                    .frame(minWidth: 356, minHeight: 720)
            }
    }
}

Build docs developers (and LLMs) love