Skip to content

Extract service initialization for headless operation#2

Closed
Newarr wants to merge 7 commits intorefactor/derive-isrecording-from-statefrom
feature/headless-service-init
Closed

Extract service initialization for headless operation#2
Newarr wants to merge 7 commits intorefactor/derive-isrecording-from-statefrom
feature/headless-service-init

Conversation

@Newarr
Copy link
Copy Markdown
Owner

@Newarr Newarr commented Mar 20, 2026

Problem

TranscriptionEngine, TranscriptLogger, RefinementEngine, and AudioRecorder are created inside ContentView.task. This means background recording is impossible without a visible main window -- the services simply don't exist.

Solution

Add ensureServicesInitialized(settings:coordinator:) on AppRuntime with an idempotency guard. Coordinator-owned services are created once on first call (from AppDelegate or ContentView, whichever runs first). ContentView.task now only creates view-local services (KnowledgeBase, SuggestionEngine).

Before After
ContentView.task calls makeServices() and assigns all 6 services ensureServicesInitialized() creates coordinator services; ContentView creates only view-local services
Services nil until window appears Services available as soon as app is ready
Background recording impossible Background recording enabled

Changed files

File Change
AppRuntime.swift Add ensureServicesInitialized() with didInitializeServices guard
ContentView.swift Call ensureServicesInitialized(), create only KnowledgeBase + SuggestionEngine locally

Test plan

  • Launch app, verify transcription works normally (services initialized via ContentView path)
  • Verify no duplicate service creation (check logs for double model loading)
  • Existing ui-smoke tests pass

PR 2 of 4 in the menu bar background mode series.
Depends on: #1 Derive isRecording from state machine
Next: #3 Add menu bar status item and popover

@Newarr Newarr mentioned this pull request Mar 20, 2026
9 tasks
@Newarr Newarr force-pushed the refactor/derive-isrecording-from-state branch from 08cabe2 to 705ff94 Compare March 20, 2026 18:48
@Newarr Newarr force-pushed the feature/headless-service-init branch from c522a3a to 0a8df8c Compare March 20, 2026 18:48
TranscriptionEngine and other coordinator-owned services were created
inside ContentView.task, making background recording impossible without
a visible window. Add ensureServicesInitialized() on AppRuntime so
services can be created early from AppDelegate. ContentView.task now
only creates view-local services (KnowledgeBase, SuggestionEngine).
@Newarr Newarr force-pushed the refactor/derive-isrecording-from-state branch from 705ff94 to 27fd880 Compare March 20, 2026 19:01
@Newarr Newarr force-pushed the feature/headless-service-init branch from 0a8df8c to 049c999 Compare March 20, 2026 19:01
yazins-ai and others added 6 commits March 20, 2026 22:13
Add acoustic echo cancellation via Apple Voice Processing. Enables setVoiceProcessingEnabled on AVAudioEngine mic input to cancel speaker echo that causes duplicate transcription. On by default with toggle in Settings > Recording. Closes yazinsai#88
Redesign NotesView: 2-tab model with batch cleanup

Replaces the 3-state Raw/Refined/Notes detail view with a clean 2-tab segmented picker (Transcript / Notes). Adds batch transcript cleanup via TranscriptCleanupEngine for on-demand refinement of past sessions.

Based on the design direction from @Newarr in PRs yazinsai#82 and yazinsai#83 — thank you for the original work! Reimplemented to keep drain() timeout at 5s and strip unrelated scope changes.

Closes yazinsai#82, closes yazinsai#83.
Add structured Markdown meeting output (openoats/v1)

Produces `.md` files in ~/Documents/OpenOats/ alongside existing `.txt` output.
YAML frontmatter with date, duration, participants, ASR engine, and meeting app.
Body sections: Summary, Action Items, Decisions, Transcript (high-signal first).
Speaker-attributed transcript lines with relative timestamps.

Three processing stages: raw transcript (always written at finalization),
LLM-enriched sections inserted when notes are generated. Existing .txt
output is preserved unchanged.

Includes format specification, example transcript, and 42 unit tests.

Closes no issues — new capability.
Derive isRecording from coordinator state machine

Replace writable stored `_isRecording` property with a computed property
that reads directly from the coordinator's authoritative `MeetingState`.
Eliminates stale-value risk from the 100ms polling loop.

Also adds `MeetingMetadata.manual()` static factory to deduplicate inline
metadata construction across call sites.
Newarr pushed a commit that referenced this pull request Mar 22, 2026


- Make cancel() async and await task completion to prevent data races (#1)
- Move session-switch guard before backfillRefinedText to prevent stale writes (#3)
- Cancel cleanup engine in teardownMeetingDetection (#4)
- Add .pre-llm.md backup before overwriting Markdown with LLM sections (yazinsai#10)
- Add safety documentation for nonisolated(unsafe) vars (#2)
- Add unit tests for chunkRecords and parseResponse (#5)

https://claude.ai/code/session_01QTKjQDQpoVqFrPJM8bp218
@Newarr Newarr closed this Mar 30, 2026
@Newarr Newarr deleted the feature/headless-service-init branch March 30, 2026 11:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants