feat: local HTTP control API for external recording start/stop#499
Open
ryanhugh wants to merge 1 commit into
Open
feat: local HTTP control API for external recording start/stop#499ryanhugh wants to merge 1 commit into
ryanhugh wants to merge 1 commit into
Conversation
Adds a localhost-only (127.0.0.1:5172) HTTP API inside the Tauri app so
other local processes (scripts, Raycast, automations) can control
recordings:
- GET /status -> {"recording": bool}
- POST /start -> {"title"?, "metadata"?}; optional meeting title and a
free-form metadata block that is saved as the first transcript segment
(so it appears at the top of the meeting and feeds summarization)
- POST /stop -> stops recording and runs the normal save flow
Implementation reuses the existing tray mechanisms: start goes through
the frontend auto-start flow (sessionStorage flag + navigation), stop
goes through a new shared stop_recording_and_notify() helper that the
two tray handlers now also use instead of duplicating the logic.
Also fixes two pre-existing bugs found along the way:
- recordingService.startRecordingWithDevices passed snake_case arg keys
to a camelCase-expecting Tauri v2 command, so the selected devices and
meeting name were silently dropped (every meeting got the default
"Meeting YYYY-MM-DD..." title regardless of what the UI generated)
- summary/mod.rs and summary_engine/mod.rs re-exported only the
__cmd__* macros, missing the __tauri_command_name_* macros that the
locked tauri 2.11 generate_handler! requires, breaking clean builds
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a localhost-only HTTP control API (
127.0.0.1:5172) inside the Tauri app so other local processes (scripts, Raycast, window managers, automations) can control recordings:GET /status{"recording": bool}POST /start{"title"?: string, "metadata"?: string}— starts a recording. Optional custom meeting title; optional free-form metadata block that is saved as the first transcript segment (top of the meeting, included in summarization). Returns200once recording actually starts,409if already recording,504if the frontend refuses (e.g. no transcription model).POST /stop409if not recording.Example:
How
The API deliberately reuses the existing tray mechanisms rather than inventing a new path:
sessionStorageand triggers the same auto-start flow the tray uses (useRecordingStart), so model checks, device selection, meeting state, and save flow behave exactly like a button click.recording_commands::stop_recording_and_notify()helper — both tray handlers were duplicating ~30 lines of this logic and now call the same helper.sequence_id: -1, sorts before all real segments) both live and at save time, so it survives mid-recording page reloads and state resyncs.axumon the existing tokio runtime, bound to127.0.0.1only (same trust level as the tray). Bind failure logs and degrades gracefully.Pre-existing bugs fixed along the way
recordingService.startRecordingWithDevicespassed snake_case arg keys (mic_device_name,meeting_name) to a Tauri v2 command expecting camelCase, so Rust always receivedNone(log:Mic: None, System: None, Meeting: None) and every meeting got the defaultMeeting YYYY-MM-DD…title regardless of the UI-generated one.mainfail with the committed Cargo.lock (tauri 2.11.2):generate_handler!requires the generated__tauri_command_name_*macros, butsummary/mod.rsandsummary_engine/mod.rsre-exported only the old__cmd__*ones → 15 ×E0433. Added the missing re-exports.Testing
Verified end-to-end on macOS (Apple Silicon, dev build):
GET /status→{"recording":false}/{"recording":true}✅POST /startwith title + metadata → app navigates home, recording starts,200 {"status":"recording","title":"API Test Round 2"}; Rust log confirmsMeeting: Some("API Test Round 2")✅POST /startwhile recording →409✅ ;POST /stopwhile idle →409✅POST /stop→ normal save flow; SQLite shows the meeting titledAPI Test Round 2with the metadata block as the first segment (audio_start_time = 0) followed by the real transcribed speech ✅cargo checkandtsc --noEmitclean ✅🤖 Generated with Claude Code