Building Granola.ai clone macOS desktop app

In this repository, I'd like to start buiilding a https://www.granola.ai/ clone. Only a desktop app. Only current macOS version. I only need to cover this flow: capture system audio input & output -> transcribe -> summarize as markdown text and show on screen. We can use https://github.com/antirez/voxtral.c for transcription (spawn a subprocess and just pipe whatever it needs to input). What questions do you have that I need to answer in order to have a clean picture?

To get a clean implementation plan, I need decisions on these points:

  1. What stack do you want for the desktop app shell: Electron, Tauri, native Swift/SwiftUI, or “use whatever fits this repo best”?
  2. For macOS target, should we support only a single version (macOS 15.x for example) or “latest major + previous”?
  3. For “capture system audio input & output,” do you mean:
    • microphone + system output mixed together into one stream, or
    • two separate streams (mic vs output) that we can tag in transcript?
  4. Is system-output capture allowed to require a virtual audio device (e.g. BlackHole), or must it work with no external driver install?
  5. Should capture be global (all system output) or limited to a selected app/window?
  6. Do you want live transcription while recording, or only transcription after stopping capture?
  7. For voxtral.c, do you already have a model/runtime choice, or should I pick defaults and design a pluggable subprocess wrapper?
  8. Which summarization path do you want:
    • local model,
    • API model (OpenAI/Anthropic/etc.),
    • or placeholder summarizer first?
  9. What summary format do you want exactly: fixed Markdown template (sections like Key Points, Decisions, Action Items) or free-form?
  10. Should notes/transcripts be persisted locally (history list), or only in-memory for now?
  11. Any hard constraints on privacy/security: fully offline only, no cloud calls, encrypted local storage, etc.?
  12. What is the “good enough” UX for v1:
  • single screen with Start/Stop + transcript + markdown summary,
  • or include device selectors, status indicators, and error/permission flows from day one?
  1. Do you want speaker/source attribution in transcript (Mic, System) and timestamps?
  2. Should summary regenerate continuously as transcript grows, or only once at the end?
  3. For v1, are we okay with unsigned/dev build runs, or do you want proper app signing/notarization setup early?

If you answer these, I can turn it into a concrete build plan and start implementing immediately.

1. What would you be most comfortable with? 2. Just whatever we're currently using for dev. Don't bother with this 3. I'd love to be able in transcriptions to determine speakers - so whatever will make this possible 4. no external driver. I know this is possible in macos using some system APIs, that just need explicit user permission to use 5. does it matter? 6. whatever is simpler to achieve 7. that repo has a CLI provided. read its readme 8. api model. can be openai. maybe we can use some ai sdk that will abstract this away? 9. free form 10. whatver simplest. in-memory for now 11. I don't care right now 12. single screen 13. yes 14. at the end - I think that's simpler. but good question! 15. unsigned/dev

Perfect — with your answers, we can move fast.

Given the repo is currently empty, my recommendation is:

  1. Swift + SwiftUI desktop app (most natural for macOS-only audio permissions/capture).
  2. Global capture of system output using Apple APIs (ScreenCaptureKit) + mic capture (AVFoundation), no external driver.
  3. Source attribution as Mic vs System in transcript (true per-person diarization from mixed system audio is not reliably possible in v1).
  4. Record first, then transcribe once on stop (simpler and more stable).
  5. Summarize at the end via OpenAI API behind a tiny provider interface (so we can swap providers later).

Only 4 final decisions needed from you:

  1. Is Mic vs System attribution acceptable instead of per-human speaker IDs?
  2. Should we target English-only first or auto-detect language?
  3. Which OpenAI model do you want for summarization (or should I pick a sensible default)?
  4. Are you okay with granting Screen Recording permission (required by macOS path for system-audio capture)?

If yes, I’ll start scaffolding the app immediately.

1. it's fine. I guess transcription model has an ability to determine speakers, right? 2. whatver is default for transcription model 3. pick sensible default 4. yes don't scaffold yet. let's make an implementation plan to review

Implementation Plan (Review Draft)

  1. Build a macOS-only SwiftUI app with one screen:
  • Start/Stop capture button
  • Live status area (idle, capturing, transcribing, summarizing, done, error)
  • Transcript panel
  • Markdown summary panel
  1. Capture audio from two sources in parallel:
  • Mic via AVAudioEngine/AVFoundation
  • System output via ScreenCaptureKit stream audio
  • Keep streams logically separated so transcript segments can be tagged Mic or System
  1. Buffer capture to files (simplest stable path):
  • Write mic.wav and system.wav during recording
  • On stop, finalize both files
  • Keep everything in-memory from app perspective (no note history), but temporary audio files are used for processing
  1. Transcription pipeline via voxtral.c CLI subprocess:
  • Add a small Swift Process wrapper (TranscriptionService)
  • Invoke CLI separately for each source file (mic.wav, system.wav)
  • Parse stdout/stderr and normalize into transcript segments
  • Merge by timestamps when available; otherwise append with source tags in capture order
  1. Speaker/source labeling strategy:
  • v1 label segments as Mic and System
  • If voxtral provides diarization markers, preserve them in segment metadata
  • Display format example:
    • [00:01:12] Mic: ...
    • [00:01:15] System: ...
  1. Summarization at end using OpenAI API:
  • SummarizationService with a provider interface (AIProvider) so we can swap APIs later
  • Default model: a sensible cost/quality middle ground (gpt-4.1-mini unless you want different)
  • Prompt takes full transcript and asks for free-form Markdown summary
  • Return raw Markdown and render in app as plain text (or rich markdown view if easy)
  1. Permissions and UX/error handling:
  • Request/check Microphone permission
  • Request/check Screen Recording permission for system audio path
  • Clear action guidance when permission is missing (including “open System Settings”)
  • Show subprocess/API errors inline on the same screen
  1. Architecture (small but clean):
  • CaptureService (mic + system)
  • TranscriptionService (voxtral process wrapper)
  • SummarizationService (OpenAI call)
  • AppViewModel as orchestrator/state machine
  • Lightweight models: TranscriptSegment, SessionState, SummaryResult
  1. Verification strategy:
  • Manual smoke flow: start capture → stop → transcription appears with source tags → summary appears
  • Edge tests:
    • stop quickly (very short audio)
    • missing permissions
    • voxtral binary not found/fails
    • OpenAI key missing/network failure
  • Validate no app crash on cancellation and repeated runs
  1. Delivery phases:
  • Phase 1: UI + permissions + capture to files
  • Phase 2: voxtral integration + transcript rendering
  • Phase 3: OpenAI summarization + markdown output
  • Phase 4: stabilization and quality pass

Answer to your diarization question
voxtral may expose speaker diarization depending on model/mode, but for this flow we should treat that as a best-effort enhancement. The guaranteed v1 labeling is source-based (Mic vs System), which is robust and immediately useful.

If this plan looks good, I’ll implement Phase 1 first and keep each phase reviewable.

ok I wonder if we're going to use OpenAI API then perhaps we could use some OpenAI transcription models if exist in place of voxtral? what would be simpler?

Yes — using OpenAI for transcription too will be simpler than integrating voxtral.c right now.

Quick comparison:

  1. OpenAI transcription API (whisper-1 / newer speech models):
  • Simpler integration: one HTTP call per audio file
  • No local binary/model management
  • Fewer failure modes (no subprocess parsing, no local model setup)
  • Easy to keep Mic vs System by transcribing each file separately
  1. voxtral.c local CLI:
  • More complex integration (process lifecycle, stdout parsing, model/runtime setup)
  • Better for offline/local-first goals later
  • More moving parts during early MVP

Main tradeoff:

  • OpenAI path is easiest for v1, but cloud-dependent and paid per usage.
  • Local path is harder now, better for offline/privacy/cost control long-term.

For your MVP, I’d switch to OpenAI transcription + OpenAI summarization.
It will let us ship the end-to-end flow faster.

If you want, I can update the implementation plan to this architecture before we start building.

let's update the plan

Updated Implementation Plan (OpenAI for Transcription + Summary)

  1. Build a macOS-only SwiftUI app with one screen:
  • Start/Stop recording button
  • Status indicator: Idle, Capturing, Transcribing, Summarizing, Done, Error
  • Transcript text area
  • Markdown summary text area
  1. Capture two audio sources in parallel:
  • Mic capture via AVFoundation (AVAudioEngine/AVAudioFile)
  • System output capture via ScreenCaptureKit audio stream
  • Keep streams separate to preserve attribution (Mic vs System)
  1. Save capture to temporary files:
  • Write mic.wav and system.wav in temp dir for the active session
  • On stop, finalize files and pass them to API pipeline
  • No persistent history in v1; clear session state on next recording
  1. Transcription with OpenAI API:
  • Create TranscriptionService that uploads each file separately
  • Use a sensible default model (e.g. gpt-4o-mini-transcribe or latest equivalent available)
  • Request timestamped output if supported; fallback to plain text if not
  • Build transcript segments tagged by source:
    • [timestamp] Mic: ...
    • [timestamp] System: ...
  1. Segment merge strategy:
  • If both sources have timestamps, merge chronologically
  • If one/both don’t, render as grouped sections (Mic, System) or append in stop-order
  • Keep logic deterministic and simple
  1. Summarization with OpenAI API:
  • Create SummarizationService (provider interface included for easy future swap)
  • Default summary model: gpt-4.1-mini (balanced cost/quality)
  • Prompt: generate free-form Markdown summary from full transcript
  • Show returned Markdown directly in UI
  1. Permissions and onboarding UX:
  • Ask/check Microphone permission
  • Ask/check Screen Recording permission
  • Provide inline guidance for denied permissions and shortcut to System Settings instructions
  • Block Start until required permissions are granted
  1. App architecture:
  • CaptureService (mic + system capture lifecycle)
  • TranscriptionService (OpenAI speech-to-text)
  • SummarizationService (OpenAI text generation)
  • SessionOrchestrator / ViewModel for state machine
  • Models: TranscriptSegment, SessionStatus, CaptureArtifacts
  1. Config and secrets:
  • Read OPENAI_API_KEY from environment or local config file for dev
  • Centralize API client config (timeouts, retry for transient failures)
  • Never log raw secrets
  1. Error handling:
  • Friendly errors for:
    • missing permissions
    • no audio captured / too short recording
    • API auth/network/rate-limit failures
  • Allow retry from same screen without restarting app
  1. Verification plan:
  • Manual E2E: capture both sources → stop → transcript with source tags → markdown summary appears
  • Edge checks:
    • missing API key
    • denied permissions
    • repeated start/stop sessions
    • low-duration clip
    • offline network
  1. Delivery phases:
  • Phase 1: app skeleton + single-screen UI + permissions + dual-source capture to files
  • Phase 2: OpenAI transcription integration + source-tagged transcript rendering
  • Phase 3: OpenAI summarization + markdown output
  • Phase 4: stabilization, retries, and UX polish

If you approve, I’ll implement Phase 1 first and keep each phase separately reviewable.

let's go

Phase 1 is implemented and buildable.

Implemented:

  • Single-screen macOS UI with Start/Stop, status, transcript pane, and markdown summary pane in ContentView.swift.
  • Session orchestration/state machine in RecorderViewModel.swift with permission checks, start/stop flow, and phase placeholder states (transcribing/done).
  • Dual-source capture service in AudioCaptureService.swift:
    • mic capture via AVAudioEngine to mic.wav
    • system audio capture via ScreenCaptureKit to system.m4a
    • temporary per-session output directory under macOS temp
  • Session/permission models in Models.swift.
  • Sandbox entitlements updated for mic + network in Softwarola.entitlements.

Verification:

  • xcodebuildmcp macos build --workspace-path ./Softwarola.xcworkspace --scheme Softwarola passes.
  • xcodebuildmcp swift-package test --package-path ./SoftwarolaPackage passes.

Notes:

  • There is one compile warning in AudioCaptureService.swift about AVAssetWriter Sendable capture in finishWriting completion; non-blocking for now.
  • This workspace is not initialized as a git repo, so there’s no git status to show.

Next logical step is Phase 2: add OpenAI transcription API integration and replace the placeholder transcript text with real source-tagged segments.

how to run the app locally?
  1. From the repo root, build and run with:
xcodebuildmcp macos build-and-run --workspace-path "./Softwarola.xcworkspace" --scheme "Softwarola"
  1. Or open in Xcode and run manually:
  1. First launch permissions you must allow:
  • Microphone
  • Screen Recording (for system audio)
  1. If macOS says permissions changed but capture still fails:
  • Quit app
  • Re-open app (sometimes required after Screen Recording permission grant)

For now, app flow is: Start CaptureStop Capture → shows paths to captured mic.wav and system.m4a files in the transcript panel.

do 1

App is running locally.

Executed:

xcodebuildmcp macos build-and-run --workspace-path "./Softwarola.xcworkspace" --scheme "Softwarola"

Result:

  • Build succeeded
  • App launched at:
    /Users/mk/Library/Developer/Xcode/DerivedData/Softwarola-afkrvxnymwnoghexqsptaeuygalg/Build/Products/Debug/Softwarola.app

If you want, I can proceed directly with Phase 2 (OpenAI transcription integration) now.

it crashed after I clicked start recording: ------------------------------------- Translated Report (Full Report Below) ------------------------------------- Process: Softwarola [15128] Path: /Users/USER/Library/Developer/Xcode/DerivedData/Softwarola-afkrvxnymwnoghexqsptaeuygalg/Build/Products/Debug/Softwarola.app/Contents/MacOS/Softwarola Identifier: io.sentry.softwarola Version: 1.0 (1) Code Type: ARM-64 (Native) Role: Foreground Parent Process: launchd [1] Coalition: io.sentry.softwarola [57577] User ID: 501 Date/Time: 2026-02-26 12:23:11.9915 +0100 Launch Time: 2026-02-26 12:23:08.2244 +0100 Hardware Model: Mac16,7 OS Version: macOS 26.3 (25D125) Release Type: User Crash Reporter Key: E86ABAE6-E342-8616-E1CD-CC81C7EFA740 Incident Identifier: D8C39678-1AC1-490C-8365-E4FEEC821CF5 Sleep/Wake UUID: 17D845F9-1645-4D25-B631-38CFDE19F3E2 Time Awake Since Boot: 220000 seconds Time Since Wake: 1309 seconds System Integrity Protection: enabled Triggered by Thread: 2, Dispatch Queue: com.apple.root.default-qos Exception Type: EXC_CRASH (SIGABRT) Exception Codes: 0x0000000000000000, 0x0000000000000000 Termination Reason: Namespace TCC, Code 0, This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSMicrophoneUsageDescription key with a string value explaining to the user how the app uses this data. Thread 0:: Dispatch queue: com.apple.main-thread 0 libsystem_kernel.dylib 0x19abc8c34 mach_msg2_trap + 8 1 libsystem_kernel.dylib 0x19abdb028 mach_msg2_internal + 76 2 libsystem_kernel.dylib 0x19abd198c mach_msg_overwrite + 484 3 libsystem_kernel.dylib 0x19abc8fb4 mach_msg + 24 4 CoreFoundation 0x19acaabb0 __CFRunLoopServiceMachPort + 160 5 CoreFoundation 0x19aca9508 __CFRunLoopRun + 1188 6 CoreFoundation 0x19ad63f3c _CFRunLoopRunSpecificWithOptions + 532 7 HIToolbox 0x1a77e5790 RunCurrentEventLoopInMode + 316 8 HIToolbox 0x1a77e8ab8 ReceiveNextEventCommon + 488 9 HIToolbox 0x1a7972b64 _BlockUntilNextEventMatchingListInMode + 48 10 AppKit 0x19f5c5014 _DPSBlockUntilNextEventMatchingListInMode + 236 11 AppKit 0x19f0c2e48 _DPSNextEvent + 588 12 AppKit 0x19fb89e8c -[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 688 13 AppKit 0x19fb89b98 -[NSApplication(NSEventRouting) nextEventMatchingMask:untilDate:inMode:dequeue:] + 72 14 AppKit 0x19f0bb780 -[NSApplication run] + 368 15 AppKit 0x19f0a76dc NSApplicationMain + 880 16 SwiftUI 0x1ceeef3ec specialized runApp(_:) + 168 17 SwiftUI 0x1cf2a8c88 runApp<A>(_:) + 112 18 SwiftUI 0x1cf573320 static App.main() + 224 19 Softwarola 0x104e6ddfc static SoftwarolaApp.$main() + 24 [inlined] 20 Softwarola 0x104e6ddfc main + 36 21 dyld 0x19a841d54 start + 7184 Thread 1: Thread 2 Crashed:: Dispatch queue: com.apple.root.default-qos 0 libsystem_kernel.dylib 0x19abd5aec __abort_with_payload + 8 1 libsystem_kernel.dylib 0x19abfc3b0 abort_with_payload_wrapper_internal + 104 2 libsystem_kernel.dylib 0x19abfc3e4 abort_with_payload + 16 3 TCC 0x1a13cae94 __TCC_CRASHING_DUE_TO_PRIVACY_VIOLATION__ + 172 4 TCC 0x1a13cb7e0 __TCCAccessRequest_block_invoke.229 + 628 5 TCC 0x1a13c882c __tccd_send_message_block_invoke + 632 6 libxpc.dylib 0x19a8ece74 _xpc_connection_reply_callout + 124 7 libxpc.dylib 0x19a8ecd68 _xpc_connection_call_reply_async + 96 8 libdispatch.dylib 0x19aa68b04 <deduplicated_symbol> + 16 9 libdispatch.dylib 0x19aa6caf8 _dispatch_mach_msg_async_reply_invoke + 340 10 libdispatch.dylib 0x19aa6217c _dispatch_root_queue_drain_deferred_item + 216 11 libdispatch.dylib 0x19aa619e4 _dispatch_kevent_worker_thread + 520 12 libsystem_pthread.dylib 0x19ac07e84 _pthread_wqthread + 348 13 libsystem_pthread.dylib 0x19ac06b9c start_wqthread + 8 Thread 3: Thread 4:: com.apple.NSEventThread 0 libsystem_kernel.dylib 0x19abc8c34 mach_msg2_trap + 8 1 libsystem_kernel.dylib 0x19abdb028 mach_msg2_internal + 76 2 libsystem_kernel.dylib 0x19abd198c mach_msg_overwrite + 484 3 libsystem_kernel.dylib 0x19abc8fb4 mach_msg + 24 4 CoreFoundation 0x19acaabb0 __CFRunLoopServiceMachPort + 160 5 CoreFoundation 0x19aca9508 __CFRunLoopRun + 1188 6 CoreFoundation 0x19ad63f3c _CFRunLoopRunSpecificWithOptions + 532 7 AppKit 0x19f152a34 _NSEventThread + 184 8 libsystem_pthread.dylib 0x19ac0bc08 _pthread_start + 136 9 libsystem_pthread.dylib 0x19ac06ba8 thread_start + 8 Thread 5: Thread 6: Thread 2 crashed with ARM Thread State (64-bit): x0: 0x000000000000000b x1: 0x0000000000000000 x2: 0x000000083742c5b0 x3: 0x000000000000001d x4: 0x000000083742c5e0 x5: 0x0000000000000000 x6: 0x00f6000004220122 x7: 0x0000000000000000 x8: 0x0000000000000020 x9: 0x553ffeb02b880098 x10: 0x0100000100000000 x11: 0x0000000000644d57 x12: 0x06cb862302051004 x13: 0x0200000110000d40 x14: 0x0000020000001000 x15: 0x0200000010000c18 x16: 0x0000000000000209 x17: 0x0000000208444fa8 x18: 0x0000000000000000 x19: 0x0000000000000000 x20: 0x000000083742c5e0 x21: 0x000000000000001d x22: 0x000000083742c5b0 x23: 0x0000000000000000 x24: 0x000000000000000b x25: 0x0000000837bff5c0 x26: 0x0000000000000000 x27: 0x0000000000000000 x28: 0x0000000000000000 fp: 0x000000016b0a6640 lr: 0x000000019abfc3b0 sp: 0x000000016b0a6600 pc: 0x000000019abd5aec cpsr: 0x40000000 far: 0x0000000000000000 esr: 0x56000080 (Syscall) Binary Images: 0x104e6c000 - 0x104e8ffff io.sentry.softwarola (1.0) <4cefaf6d-0580-3eb3-9a5f-370ca5989f7f> /Users/USER/Library/Developer/Xcode/DerivedData/Softwarola-afkrvxnymwnoghexqsptaeuygalg/Build/Products/Debug/Softwarola.app/Contents/MacOS/Softwarola 0x10d86c000 - 0x10d877fff libobjc-trampolines.dylib (*) <f26af954-d1f7-31aa-9981-1bad216149d9> /usr/lib/libobjc-trampolines.dylib 0x119008000 - 0x11983ffff com.apple.AGXMetalG16X (345.20.4) <b9cc44be-3f8e-3fdc-9153-f4bb268113a0> /System/Library/Extensions/AGXMetalG16X.bundle/Contents/MacOS/AGXMetalG16X 0x19abc8000 - 0x19ac0449f libsystem_kernel.dylib (*) <b809799c-0ec9-3ee1-b730-342bdbf14e03> /usr/lib/system/libsystem_kernel.dylib 0x19ac4b000 - 0x19b1942bf com.apple.CoreFoundation (6.9) <02762698-9950-3c66-8116-a3a565972a49> /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation 0x1a7724000 - 0x1a7a2727f com.apple.HIToolbox (2.1.1) <fa4beac8-9a1e-3071-b669-bd2794e9fe3b> /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox 0x19f0a3000 - 0x1a07cebdf com.apple.AppKit (6.9) <07dcc67f-25b2-3f2c-b92e-6fc579455989> /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit 0x1cedde000 - 0x1d0524f7f com.apple.SwiftUI (7.3.2) <a01a90c1-cc14-30ae-8fb9-e5173c413f95> /System/Library/Frameworks/SwiftUI.framework/Versions/A/SwiftUI 0x19a839000 - 0x19a8d8713 dyld (*) <bc4db5f4-1c64-3706-8006-73b78c3e1f1a> /usr/lib/dyld 0x0 - 0xffffffffffffffff ??? (*) <00000000-0000-0000-0000-000000000000> ??? 0x1a13c6000 - 0x1a13eac77 com.apple.TCC (1.0) <2be6a2e2-a205-35d1-a802-ffaa38e1a91a> /System/Library/PrivateFrameworks/TCC.framework/Versions/A/TCC 0x19a8dd000 - 0x19a93207f libxpc.dylib (*) <3b264f68-2825-3790-8796-4b49581d6425> /usr/lib/system/libxpc.dylib 0x19aa4d000 - 0x19aa93e5f libdispatch.dylib (*) <4c58ab31-f363-3e75-a8f8-302105812dbf> /usr/lib/system/libdispatch.dylib 0x19ac05000 - 0x19ac11acb libsystem_pthread.dylib (*) <0596a7b6-bce2-3f06-a2e8-3eaab5371ed8> /usr/lib/system/libsystem_pthread.dylib External Modification Summary: Calls made by other processes targeting this process: task_for_pid: 0 thread_create: 0 thread_set_state: 0 Calls made by this process: task_for_pid: 0 thread_create: 0 thread_set_state: 0 Calls made by all processes on this machine: task_for_pid: 0 thread_create: 0 thread_set_state: 0 VM Region Summary: ReadOnly portion of Libraries: Total=1.8G resident=0K(0%) swapped_out_or_unallocated=1.8G(100%) Writable regions: Total=145.0M written=545K(0%) resident=545K(0%) swapped_out=0K(0%) unallocated=144.4M(100%) VIRTUAL REGION REGION TYPE SIZE COUNT (non-coalesced) =========== ======= ======= .note.gnu.proper 320 1 Accelerate framework 128K 1 Activity Tracing 256K 1 AttributeGraph Data 1024K 1 ColorSync 16K 1 CoreAnimation 2368K 39 CoreGraphics 48K 3 CoreUI image data 256K 2 Foundation 48K 2 Kernel Alloc Once 32K 1 MALLOC 129.4M 26 MALLOC guard page 3712K 4 STACK GUARD 56.1M 7 Stack 11.2M 7 VM_ALLOCATE 160K 10 __AUTH 5755K 636 __AUTH_CONST 87.7M 1011 __CTF 824 1 __DATA 34.2M 960 __DATA_CONST 32.6M 1019 __DATA_DIRTY 8339K 871 __FONT_DATA 2352 1 __INFO_FILTER 8 1 __LINKEDIT 590.1M 4 __LLVM_COV 16K 1 __OBJC_RO 78.4M 1 __OBJC_RW 2571K 1 __TEXT 1.2G 1041 __TPRO_CONST 128K 2 mapped file 308.4M 34 page table in kernel 545K 1 shared memory 1376K 12 =========== ======= ======= TOTAL 2.5G 5703 ----------- Full Report ----------- {"app_name":"Softwarola","timestamp":"2026-02-26 12:23:15.00 +0100","app_version":"1.0","slice_uuid":"4cefaf6d-0580-3eb3-9a5f-370ca5989f7f","build_version":"1","platform":1,"bundleID":"io.sentry.softwarola","share_with_app_devs":0,"is_first_party":0,"bug_type":"309","os_version":"macOS 26.3 (25D125)","roots_installed":0,"name":"Softwarola","incident_id":"D8C39678-1AC1-490C-8365-E4FEEC821CF5"} { "uptime" : 220000, "procRole" : "Foreground", "version" : 2, "userID" : 501, "deployVersion" : 210, "modelCode" : "Mac16,7", "coalitionID" : 57577, "osVersion" : { "train" : "macOS 26.3", "build" : "25D125", "releaseType" : "User" }, "captureTime" : "2026-02-26 12:23:11.9915 +0100", "codeSigningMonitor" : 2, "incident" : "D8C39678-1AC1-490C-8365-E4FEEC821CF5", "pid" : 15128, "translated" : false, "cpuType" : "ARM-64", "procLaunch" : "2026-02-26 12:23:08.2244 +0100", "procStartAbsTime" : 5418887249360, "procExitAbsTime" : 5418977541854, "procName" : "Softwarola", "procPath" : "\/Users\/USER\/Library\/Developer\/Xcode\/DerivedData\/Softwarola-afkrvxnymwnoghexqsptaeuygalg\/Build\/Products\/Debug\/Softwarola.app\/Contents\/MacOS\/Softwarola", "bundleInfo" : {"CFBundleShortVersionString":"1.0","CFBundleVersion":"1","CFBundleIdentifier":"io.sentry.softwarola"}, "storeInfo" : {"deviceIdentifierForVendor":"901148CD-CEE9-5F95-B22F-B967C51308E1","thirdParty":true}, "parentProc" : "launchd", "parentPid" : 1, "coalitionName" : "io.sentry.softwarola", "crashReporterKey" : "E86ABAE6-E342-8616-E1CD-CC81C7EFA740", "appleIntelligenceStatus" : {"state":"unavailable","reasons":["selectedLanguageDoesNotMatchSelectedSiriLanguageInfo(system: pl, siri: en-GB)","selectedLanguageDoesNotMatchSelectedSiriLanguage","selectedLanguageIneligibleInfo(pl)","selectedLanguageIneligible"]}, "developerMode" : 1, "codeSigningID" : "io.sentry.softwarola", "codeSigningTeamID" : "", "codeSigningFlags" : 570425861, "codeSigningValidationCategory" : 10, "codeSigningTrustLevel" : 4294967295, "codeSigningAuxiliaryInfo" : 0, "instructionByteStream" : {"beforePC":"fyMD1f17v6n9AwCRxc7\/l78DAJH9e8Go\/w9f1sADX9YwQYDSARAA1A==","atPC":"AwEAVH8jA9X9e7+p\/QMAkbrO\/5e\/AwCR\/XvBqP8PX9bAA1\/WkDKA0g=="}, "bootSessionUUID" : "3A3EF305-8BC5-4E06-A518-4BDFC09FB5F0", "wakeTime" : 1309, "sleepWakeUUID" : "17D845F9-1645-4D25-B631-38CFDE19F3E2", "sip" : "enabled", "exception" : {"codes":"0x0000000000000000, 0x0000000000000000","rawCodes":[0,0],"type":"EXC_CRASH","signal":"SIGABRT"}, "termination" : {"flags":518,"code":0,"namespace":"TCC","details":["This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSMicrophoneUsageDescription key with a string value explaining to the user how the app uses this data."]}, "extMods" : {"caller":{"thread_create":0,"thread_set_state":0,"task_for_pid":0},"system":{"thread_create":0,"thread_set_state":0,"task_for_pid":0},"targeted":{"thread_create":0,"thread_set_state":0,"task_for_pid":0},"warnings":0}, "faultingThread" : 2, "threads" : [{"id":6573345,"threadState":{"x":[{"value":268451845},{"value":21592279046},{"value":8589934592},{"value":15440407429120},{"value":0},{"value":15440407429120},{"value":2},{"value":4294967295},{"value":0},{"value":17179869184},{"value":0},{"value":2},{"value":0},{"value":0},{"value":3595},{"value":0},{"value":18446744073709551569},{"value":8728630712},{"value":0},{"value":4294967295},{"value":2},{"value":15440407429120},{"value":0},{"value":15440407429120},{"value":6089675320},{"value":8589934592},{"value":21592279046},{"value":18446744073709550527},{"value":4412409862}],"flavor":"ARM_THREAD_STATE64","lr":{"value":6891089960},"cpsr":{"value":0},"fp":{"value":6089675168},"sp":{"value":6089675088},"esr":{"value":1442840704,"description":"(Syscall)"},"pc":{"value":6891015220},"far":{"value":0}},"queue":"com.apple.main-thread","frames":[{"imageOffset":3124,"symbol":"mach_msg2_trap","symbolLocation":8,"imageIndex":3},{"imageOffset":77864,"symbol":"mach_msg2_internal","symbolLocation":76,"imageIndex":3},{"imageOffset":39308,"symbol":"mach_msg_overwrite","symbolLocation":484,"imageIndex":3},{"imageOffset":4020,"symbol":"mach_msg","symbolLocation":24,"imageIndex":3},{"imageOffset":392112,"symbol":"__CFRunLoopServiceMachPort","symbolLocation":160,"imageIndex":4},{"imageOffset":386312,"symbol":"__CFRunLoopRun","symbolLocation":1188,"imageIndex":4},{"imageOffset":1150780,"symbol":"_CFRunLoopRunSpecificWithOptions","symbolLocation":532,"imageIndex":4},{"imageOffset":792464,"symbol":"RunCurrentEventLoopInMode","symbolLocation":316,"imageIndex":5},{"imageOffset":805560,"symbol":"ReceiveNextEventCommon","symbolLocation":488,"imageIndex":5},{"imageOffset":2419556,"symbol":"_BlockUntilNextEventMatchingListInMode","symbolLocation":48,"imageIndex":5},{"imageOffset":5382164,"symbol":"_DPSBlockUntilNextEventMatchingListInMode","symbolLocation":236,"imageIndex":6},{"imageOffset":130632,"symbol":"_DPSNextEvent","symbolLocation":588,"imageIndex":6},{"imageOffset":11431564,"symbol":"-[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:]","symbolLocation":688,"imageIndex":6},{"imageOffset":11430808,"symbol":"-[NSApplication(NSEventRouting) nextEventMatchingMask:untilDate:inMode:dequeue:]","symbolLocation":72,"imageIndex":6},{"imageOffset":100224,"symbol":"-[NSApplication run]","symbolLocation":368,"imageIndex":6},{"imageOffset":18140,"symbol":"NSApplicationMain","symbolLocation":880,"imageIndex":6},{"imageOffset":1119212,"symbol":"specialized runApp(_:)","symbolLocation":168,"imageIndex":7},{"imageOffset":5024904,"symbol":"runApp<A>(_:)","symbolLocation":112,"imageIndex":7},{"imageOffset":7951136,"symbol":"static App.main()","symbolLocation":224,"imageIndex":7},{"imageOffset":7676,"sourceFile":"SoftwarolaApp.swift","symbol":"static SoftwarolaApp.$main()","imageIndex":0,"symbolLocation":24,"inline":true},{"imageOffset":7676,"sourceFile":"SoftwarolaApp.swift","symbol":"main","symbolLocation":36,"imageIndex":0},{"imageOffset":36180,"symbol":"start","symbolLocation":7184,"imageIndex":8}]},{"id":6573398,"frames":[],"threadState":{"x":[{"value":6090240000},{"value":5635},{"value":6089703424},{"value":0},{"value":409604},{"value":18446744073709551615},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0}],"flavor":"ARM_THREAD_STATE64","lr":{"value":0},"cpsr":{"value":0},"fp":{"value":0},"sp":{"value":6090240000},"esr":{"value":1442840704,"description":"(Syscall)"},"pc":{"value":6891269012},"far":{"value":0}}},{"triggered":true,"id":6573399,"threadState":{"x":[{"value":11},{"value":0},{"value":35286861232},{"value":29},{"value":35286861280},{"value":0},{"value":69242844340158754},{"value":0},{"value":32},{"value":6142908449354678424},{"value":72057598332895232},{"value":6573399},{"value":489632469415694340},{"value":144115192639262016},{"value":2199023259648},{"value":144115188344294424},{"value":521},{"value":8728629160},{"value":0},{"value":0},{"value":35286861280},{"value":29},{"value":35286861232},{"value":0},{"value":11},{"value":35295065536},{"value":0},{"value":0},{"value":0}],"flavor":"ARM_THREAD_STATE64","lr":{"value":6891226032},"cpsr":{"value":1073741824},"fp":{"value":6090810944},"sp":{"value":6090810880},"esr":{"value":1442840704,"description":"(Syscall)"},"pc":{"value":6891068140,"matchesCrashFrame":1},"far":{"value":0}},"queue":"com.apple.root.default-qos","frames":[{"imageOffset":56044,"symbol":"__abort_with_payload","symbolLocation":8,"imageIndex":3},{"imageOffset":213936,"symbol":"abort_with_payload_wrapper_internal","symbolLocation":104,"imageIndex":3},{"imageOffset":213988,"symbol":"abort_with_payload","symbolLocation":16,"imageIndex":3},{"imageOffset":20116,"symbol":"__TCC_CRASHING_DUE_TO_PRIVACY_VIOLATION__","symbolLocation":172,"imageIndex":10},{"imageOffset":22496,"symbol":"__TCCAccessRequest_block_invoke.229","symbolLocation":628,"imageIndex":10},{"imageOffset":10284,"symbol":"__tccd_send_message_block_invoke","symbolLocation":632,"imageIndex":10},{"imageOffset":65140,"symbol":"_xpc_connection_reply_callout","symbolLocation":124,"imageIndex":11},{"imageOffset":64872,"symbol":"_xpc_connection_call_reply_async","symbolLocation":96,"imageIndex":11},{"imageOffset":113412,"symbol":"<deduplicated_symbol>","symbolLocation":16,"imageIndex":12},{"imageOffset":129784,"symbol":"_dispatch_mach_msg_async_reply_invoke","symbolLocation":340,"imageIndex":12},{"imageOffset":86396,"symbol":"_dispatch_root_queue_drain_deferred_item","symbolLocation":216,"imageIndex":12},{"imageOffset":84452,"symbol":"_dispatch_kevent_worker_thread","symbolLocation":520,"imageIndex":12},{"imageOffset":11908,"symbol":"_pthread_wqthread","symbolLocation":348,"imageIndex":13},{"imageOffset":7068,"symbol":"start_wqthread","symbolLocation":8,"imageIndex":13}]},{"id":6573402,"frames":[],"threadState":{"x":[{"value":6091386880},{"value":19459},{"value":6090850304},{"value":0},{"value":409604},{"value":18446744073709551615},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0}],"flavor":"ARM_THREAD_STATE64","lr":{"value":0},"cpsr":{"value":0},"fp":{"value":0},"sp":{"value":6091386880},"esr":{"value":1442840704,"description":"(Syscall)"},"pc":{"value":6891269012},"far":{"value":0}}},{"id":6573420,"name":"com.apple.NSEventThread","threadState":{"x":[{"value":268451845},{"value":21592279046},{"value":8589934592},{"value":95670396518400},{"value":0},{"value":95670396518400},{"value":2},{"value":4294967295},{"value":0},{"value":17179869184},{"value":0},{"value":2},{"value":0},{"value":0},{"value":22275},{"value":0},{"value":18446744073709551569},{"value":8728630712},{"value":0},{"value":4294967295},{"value":2},{"value":95670396518400},{"value":0},{"value":95670396518400},{"value":6091956360},{"value":8589934592},{"value":21592279046},{"value":18446744073709550527},{"value":4412409862}],"flavor":"ARM_THREAD_STATE64","lr":{"value":6891089960},"cpsr":{"value":0},"fp":{"value":6091956208},"sp":{"value":6091956128},"esr":{"value":1442840704,"description":"(Syscall)"},"pc":{"value":6891015220},"far":{"value":0}},"frames":[{"imageOffset":3124,"symbol":"mach_msg2_trap","symbolLocation":8,"imageIndex":3},{"imageOffset":77864,"symbol":"mach_msg2_internal","symbolLocation":76,"imageIndex":3},{"imageOffset":39308,"symbol":"mach_msg_overwrite","symbolLocation":484,"imageIndex":3},{"imageOffset":4020,"symbol":"mach_msg","symbolLocation":24,"imageIndex":3},{"imageOffset":392112,"symbol":"__CFRunLoopServiceMachPort","symbolLocation":160,"imageIndex":4},{"imageOffset":386312,"symbol":"__CFRunLoopRun","symbolLocation":1188,"imageIndex":4},{"imageOffset":1150780,"symbol":"_CFRunLoopRunSpecificWithOptions","symbolLocation":532,"imageIndex":4},{"imageOffset":719412,"symbol":"_NSEventThread","symbolLocation":184,"imageIndex":6},{"imageOffset":27656,"symbol":"_pthread_start","symbolLocation":136,"imageIndex":13},{"imageOffset":7080,"symbol":"thread_start","symbolLocation":8,"imageIndex":13}]},{"id":6573451,"frames":[],"threadState":{"x":[{"value":6092533760},{"value":47107},{"value":6091997184},{"value":0},{"value":409604},{"value":18446744073709551615},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0}],"flavor":"ARM_THREAD_STATE64","lr":{"value":0},"cpsr":{"value":0},"fp":{"value":0},"sp":{"value":6092533760},"esr":{"value":1442840704,"description":"(Syscall)"},"pc":{"value":6891269012},"far":{"value":0}}},{"id":6573452,"frames":[],"threadState":{"x":[{"value":6093107200},{"value":57359},{"value":6092570624},{"value":0},{"value":409604},{"value":18446744073709551615},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0}],"flavor":"ARM_THREAD_STATE64","lr":{"value":0},"cpsr":{"value":0},"fp":{"value":0},"sp":{"value":6093107200},"esr":{"value":1442840704,"description":"(Syscall)"},"pc":{"value":6891269012},"far":{"value":0}}}], "usedImages" : [ { "source" : "P", "arch" : "arm64", "base" : 4377198592, "CFBundleShortVersionString" : "1.0", "CFBundleIdentifier" : "io.sentry.softwarola", "size" : 147456, "uuid" : "4cefaf6d-0580-3eb3-9a5f-370ca5989f7f", "path" : "\/Users\/USER\/Library\/Developer\/Xcode\/DerivedData\/Softwarola-afkrvxnymwnoghexqsptaeuygalg\/Build\/Products\/Debug\/Softwarola.app\/Contents\/MacOS\/Softwarola", "name" : "Softwarola", "CFBundleVersion" : "1" }, { "source" : "P", "arch" : "arm64e", "base" : 4521902080, "size" : 49152, "uuid" : "f26af954-d1f7-31aa-9981-1bad216149d9", "path" : "\/usr\/lib\/libobjc-trampolines.dylib", "name" : "libobjc-trampolines.dylib" }, { "source" : "P", "arch" : "arm64e", "base" : 4714430464, "CFBundleShortVersionString" : "345.20.4", "CFBundleIdentifier" : "com.apple.AGXMetalG16X", "size" : 8617984, "uuid" : "b9cc44be-3f8e-3fdc-9153-f4bb268113a0", "path" : "\/System\/Library\/Extensions\/AGXMetalG16X.bundle\/Contents\/MacOS\/AGXMetalG16X", "name" : "AGXMetalG16X", "CFBundleVersion" : "345.20.4" }, { "source" : "P", "arch" : "arm64e", "base" : 6891012096, "size" : 246944, "uuid" : "b809799c-0ec9-3ee1-b730-342bdbf14e03", "path" : "\/usr\/lib\/system\/libsystem_kernel.dylib", "name" : "libsystem_kernel.dylib" }, { "source" : "P", "arch" : "arm64e", "base" : 6891548672, "CFBundleShortVersionString" : "6.9", "CFBundleIdentifier" : "com.apple.CoreFoundation", "size" : 5542592, "uuid" : "02762698-9950-3c66-8116-a3a565972a49", "path" : "\/System\/Library\/Frameworks\/CoreFoundation.framework\/Versions\/A\/CoreFoundation", "name" : "CoreFoundation", "CFBundleVersion" : "4302" }, { "source" : "P", "arch" : "arm64e", "base" : 7104249856, "CFBundleShortVersionString" : "2.1.1", "CFBundleIdentifier" : "com.apple.HIToolbox", "size" : 3158656, "uuid" : "fa4beac8-9a1e-3071-b669-bd2794e9fe3b", "path" : "\/System\/Library\/Frameworks\/Carbon.framework\/Versions\/A\/Frameworks\/HIToolbox.framework\/Versions\/A\/HIToolbox", "name" : "HIToolbox" }, { "source" : "P", "arch" : "arm64e", "base" : 6963212288, "CFBundleShortVersionString" : "6.9", "CFBundleIdentifier" : "com.apple.AppKit", "size" : 24296416, "uuid" : "07dcc67f-25b2-3f2c-b92e-6fc579455989", "path" : "\/System\/Library\/Frameworks\/AppKit.framework\/Versions\/C\/AppKit", "name" : "AppKit", "CFBundleVersion" : "2685.40.108" }, { "source" : "P", "arch" : "arm64e", "base" : 7765614592, "CFBundleShortVersionString" : "7.3.2", "CFBundleIdentifier" : "com.apple.SwiftUI", "size" : 24407936, "uuid" : "a01a90c1-cc14-30ae-8fb9-e5173c413f95", "path" : "\/System\/Library\/Frameworks\/SwiftUI.framework\/Versions\/A\/SwiftUI", "name" : "SwiftUI", "CFBundleVersion" : "7.3.2" }, { "source" : "P", "arch" : "arm64e", "base" : 6887280640, "size" : 653076, "uuid" : "bc4db5f4-1c64-3706-8006-73b78c3e1f1a", "path" : "\/usr\/lib\/dyld", "name" : "dyld" }, { "size" : 0, "source" : "A", "base" : 0, "uuid" : "00000000-0000-0000-0000-000000000000" }, { "source" : "P", "arch" : "arm64e", "base" : 7000055808, "CFBundleShortVersionString" : "1.0", "CFBundleIdentifier" : "com.apple.TCC", "size" : 150648, "uuid" : "2be6a2e2-a205-35d1-a802-ffaa38e1a91a", "path" : "\/System\/Library\/PrivateFrameworks\/TCC.framework\/Versions\/A\/TCC", "name" : "TCC", "CFBundleVersion" : "1" }, { "source" : "P", "arch" : "arm64e", "base" : 6887952384, "size" : 348288, "uuid" : "3b264f68-2825-3790-8796-4b49581d6425", "path" : "\/usr\/lib\/system\/libxpc.dylib", "name" : "libxpc.dylib" }, { "source" : "P", "arch" : "arm64e", "base" : 6889459712, "size" : 290400, "uuid" : "4c58ab31-f363-3e75-a8f8-302105812dbf", "path" : "\/usr\/lib\/system\/libdispatch.dylib", "name" : "libdispatch.dylib" }, { "source" : "P", "arch" : "arm64e", "base" : 6891261952, "size" : 51916, "uuid" : "0596a7b6-bce2-3f06-a2e8-3eaab5371ed8", "path" : "\/usr\/lib\/system\/libsystem_pthread.dylib", "name" : "libsystem_pthread.dylib" } ], "sharedCache" : { "base" : 6886195200, "size" : 5818417152, "uuid" : "25ae5a2a-fe2a-3998-8d4e-f3c5c6e6ceb6" }, "vmSummary" : "ReadOnly portion of Libraries: Total=1.8G resident=0K(0%) swapped_out_or_unallocated=1.8G(100%)\nWritable regions: Total=145.0M written=545K(0%) resident=545K(0%) swapped_out=0K(0%) unallocated=144.4M(100%)\n\n VIRTUAL REGION \nREGION TYPE SIZE COUNT (non-coalesced) \n=========== ======= ======= \n.note.gnu.proper 320 1 \nAccelerate framework 128K 1 \nActivity Tracing 256K 1 \nAttributeGraph Data 1024K 1 \nColorSync 16K 1 \nCoreAnimation 2368K 39 \nCoreGraphics 48K 3 \nCoreUI image data 256K 2 \nFoundation 48K 2 \nKernel Alloc Once 32K 1 \nMALLOC 129.4M 26 \nMALLOC guard page 3712K 4 \nSTACK GUARD 56.1M 7 \nStack 11.2M 7 \nVM_ALLOCATE 160K 10 \n__AUTH 5755K 636 \n__AUTH_CONST 87.7M 1011 \n__CTF 824 1 \n__DATA 34.2M 960 \n__DATA_CONST 32.6M 1019 \n__DATA_DIRTY 8339K 871 \n__FONT_DATA 2352 1 \n__INFO_FILTER 8 1 \n__LINKEDIT 590.1M 4 \n__LLVM_COV 16K 1 \n__OBJC_RO 78.4M 1 \n__OBJC_RW 2571K 1 \n__TEXT 1.2G 1041 \n__TPRO_CONST 128K 2 \nmapped file 308.4M 34 \npage table in kernel 545K 1 \nshared memory 1376K 12 \n=========== ======= ======= \nTOTAL 2.5G 5703 \n", "legacyInfo" : { "threadTriggered" : { "queue" : "com.apple.root.default-qos" } }, "logWritingSignature" : "9f67faeb233cf3a06b09a3affbb5e270ff27b1a4", "roots_installed" : 0, "bug_type" : "309", "trmStatus" : 1, "trialInfo" : { "rollouts" : [ { "rolloutId" : "61675b89201f677a9a4cbd65", "factorPackIds" : [ "65a855f5f087695cfac03d1f" ], "deploymentId" : 240000256 }, { "rolloutId" : "60f8ddccefea4203d95cbeef", "factorPackIds" : [ ], "deploymentId" : 240000025 } ], "experiments" : [ ] } } Model: Mac16,7, BootROM 13822.81.10, proc 14:10:4 processors, 24 GB, SMC Graphics: Apple M4 Pro, Apple M4 Pro, Built-In Display: M27U, 6016 x 3384, Main, MirrorOff, Online Memory Module: LPDDR5, Micron AirPort: spairport_wireless_card_type_wifi (0x14E4, 0x4388), wl0: Dec 6 2025 00:30:14 version 23.41.8.0.41.51.201 FWID 01-990604ea IO80211_driverkit-1540.16 "IO80211_driverkit-1540.16" Jan 27 2026 21:04:24 AirPort: Bluetooth: Version (null), 0 services, 0 devices, 0 incoming serial ports Network Service: Wi-Fi, AirPort, en0 Network Service: Tailscale, VPN (io.tailscale.ipn.macsys), utun4 Thunderbolt Bus: MacBook Pro, Apple Inc. Thunderbolt Bus: MacBook Pro, Apple Inc. Thunderbolt Bus: MacBook Pro, Apple Inc.

Crash fixed: it was a TCC privacy kill due to missing NSMicrophoneUsageDescription.

I added the usage description key in Config/Shared.xcconfig, which feeds the generated Info.plist:

  • INFOPLIST_KEY_NSMicrophoneUsageDescription = Softwarola needs microphone access to capture your voice during recording.

Then I rebuilt and relaunched with:

xcodebuildmcp macos build-and-run --workspace-path "./Softwarola.xcworkspace" --scheme "Softwarola"

Please try Start Capture again. You should now get a proper microphone permission prompt instead of a crash.

try again

App relaunched successfully with the latest build.

Run command used:

xcodebuildmcp macos build-and-run --workspace-path "./Softwarola.xcworkspace" --scheme "Softwarola"

Please try Start Capture now and tell me exactly what happens (prompt appears, error text in app, or another crash).

nice! it works! lets proceed to next phase

Phase 2 is in and working build-wise: Stop Capture now performs real OpenAI transcription for both audio files and renders source-tagged transcript text.

What I changed:

  • Added transcription domain models in Models.swift:
    • TranscriptSource (Mic / System)
    • TranscriptSegment
    • TranscriptionResult with ordering mode
  • Added OpenAI transcription client in OpenAITranscriptionService.swift:
    • Calls POST /v1/audio/transcriptions
    • Uploads mic.wav and system.m4a in parallel
    • Uses whisper-1 with verbose_json segment timestamps
    • Handles missing key and API errors with readable messages
  • Wired the view model to transcribe after recording stop in RecorderViewModel.swift:
    • status = .transcribing during API calls
    • Timestamped output format: [mm:ss] Mic/System: ...
    • Falls back to grouped output when timestamps are unavailable

Already verified:

  • xcodebuildmcp macos build --workspace-path "./Softwarola.xcworkspace" --scheme "Softwarola" succeeds.
  • xcodebuildmcp swift-package test --package-path ./SoftwarolaPackage succeeds.
  • App launches successfully.

To test transcription now:

  1. Ensure OPENAI_API_KEY is set in the shell before launching.
  2. Run:
xcodebuildmcp macos build-and-run --workspace-path "./Softwarola.xcworkspace" --scheme "Softwarola"
  1. Record a short sample and stop capture. Transcript pane should populate with Mic/System lines.

Natural next step:

  1. Implement Phase 3 summarization (OpenAI markdown summary from transcript).
can we have dotenv support so that we can read this env from .env?

Implemented — .env support is now in.

What changed:

How to use:

  1. Create .env in repo root:
OPENAI_API_KEY=sk-...
  1. Launch app normally (xcodebuildmcp ... build-and-run or Xcode run).
  2. It will pick up the key automatically from .env if not present in shell env.

Validation:

  • macOS build passes.
  • Swift package tests pass.
let's also add a simple Makefile with a run task which builds and runs this app

I’ll add a minimal Makefile with a run target that builds and launches via xcodebuildmcp, plus a build helper target for convenience.

Explored 1 search
Edited Makefile
+10

I added the Makefile; I’m quickly validating the targets by running make build now.

$ make build

Added a simple Makefile with:

  • make build → builds the app
  • make run → builds and runs the app

File: Makefile

I also verified make build succeeds locally.