Skip to content

tnkuehne/heimdall

Repository files navigation

Meeting Recorder

GNOME Shell extension plus Rust backend for recording meetings from the top bar.

The recorder uses wpctl to find the default microphone and current default system output, captures them through ffmpeg's Pulse-compatible PipeWire path, and writes a stereo MP3 file with microphone audio on the left channel and system audio on the right channel.

Requirements

  • GNOME Shell 46
  • ffmpeg
  • wpctl
  • gnome-extensions

On Debian/Ubuntu-like systems, the .deb package declares the runtime dependencies. For source development, install the build tools and runtime commands:

sudo apt install wireplumber ffmpeg gnome-shell

Install Rust/Cargo with rustup for development builds:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup default stable

After installing rustup, restart the shell or run source "$HOME/.cargo/env" so cargo is on PATH.

Install From Deb

Install a release package:

sudo apt install ./meeting-recorder_0.1.0_amd64.deb
gnome-extensions enable meeting-recorder@timokuehne.com

Then log out and back in if the icon does not appear.

Development Install

./scripts/install-dev.sh

Then enable the extension:

gnome-extensions enable meeting-recorder@timokuehne.com

On GNOME Wayland, log out and back in after installing extension JavaScript or preferences changes. GNOME Shell does not reliably reload changed extension modules inside the same session. If the enable command says Extension "meeting-recorder@timokuehne.com" does not exist, log out and back in, then run the enable command again.

Usage

  • Click the top bar icon to start or stop recording.
  • Use the dropdown menu to start/stop recording or open the recordings folder.
  • Use the Transcription submenu to choose Disabled, xAI, or Deepgram.
  • Open Preferences from the extension menu or GNOME Extensions to choose the recordings folder and configure API keys.
  • Recordings are saved to this folder by default:
~/Recordings/Meetings

Active recordings use a .part.mp3 filename and are renamed to .mp3 after a clean stop. Transcription is disabled until a provider is selected. When xAI or Deepgram is selected, stopping a recording automatically transcribes the saved audio and writes a Markdown transcript next to the audio file.

Backend

The .deb installs the Rust CLI on PATH:

/usr/bin/meeting-recorder

The backend binary also lives inside the extension directory:

/usr/share/gnome-shell/extensions/meeting-recorder@timokuehne.com/bin/meeting-recorder

Commands:

meeting-recorder start
meeting-recorder stop
meeting-recorder status
meeting-recorder open-folder
meeting-recorder config get
meeting-recorder config set-recordings-dir /absolute/path
meeting-recorder config reset-recordings-dir
meeting-recorder config set-post-transcribe-hook /absolute/path/to/executable
meeting-recorder config clear-post-transcribe-hook

State and logs are written under:

~/.local/state/meeting-recorder

Transcription

API keys are stored in GNOME Keyring through the Secret Service API. They are not written to the recorder state or config files.

Configure a provider from the extension menu:

  • Open Preferences.
  • Choose the transcription provider.
  • Enter the provider API key in its password row and apply it.

The CLI can also configure keys:

meeting-recorder auth set xai
meeting-recorder auth status xai
meeting-recorder auth set deepgram
meeting-recorder auth status deepgram

For non-interactive callers, auth set-stdin <provider> reads the key from stdin.

The provider selection, recordings folder, and optional post-transcribe hook are stored in:

~/.config/meeting-recorder/config.json

Transcribe a recording:

meeting-recorder transcribe ~/Recordings/Meetings/example.mp3 --provider xai
meeting-recorder transcribe ~/Recordings/Meetings/example.mp3 --provider deepgram

By default, transcription is requested with multichannel mode enabled, matching the recorder's stereo layout. The transcript Markdown document is written next to the recording as:

example.transcript.md

Use --output <path> to choose a different transcript path. Use --language <code> --format when requesting formatted xAI output, because xAI requires a language when formatting is enabled. For Deepgram, the backend uses Nova 3 with smart formatting, punctuation, utterances, diarization, and multichannel transcription enabled.

Post-transcribe Hook

Meeting Recorder can spawn one executable after a transcript has been written. The hook is fire-and-forget: the recorder does not wait for it, does not capture output, and does not manage retries or logging.

Configure it from Preferences or with:

meeting-recorder config set-post-transcribe-hook /home/timo/.config/meeting-recorder/post-transcribe

The hook receives context through environment variables:

MEETING_RECORDER_EVENT=post_transcribe
MEETING_RECORDER_PROVIDER=deepgram
MEETING_RECORDER_AUDIO_FILE=/path/to/audio.mp3
MEETING_RECORDER_TRANSCRIPT_FILE=/path/to/audio.transcript.md
MEETING_RECORDER_RECORDINGS_DIR=/path/to/recordings
MEETING_RECORDER_DURATION_SECONDS=123.456
MEETING_RECORDER_CHANNELS=2

Development

The GNOME Shell source of truth is TypeScript:

extension/extension.ts

Build the generated extension JavaScript with:

pnpm install
pnpm run build

Generated GNOME Shell files are written to build/extension and should not be committed.

GNOME/GJS types come from the published @girs/gnome-shell package pinned for GNOME Shell 46.

Build a Debian package with:

./scripts/build-deb.sh

The package is written to:

build/deb/meeting-recorder_0.1.0_amd64.deb

GitHub Actions builds and uploads the .deb automatically when a tag like v0.1.0 is pushed.

About

Native Gnome app for recording and transcribing meetings

Topics

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Contributors