agentsclimarketplace

Meeting transcription

Skill bks-lab/open-bridge/skills/meeting-transcription

Your AI coding agent starts every session knowing your repos, your clients, and how you work — a plain git repo of markdown + YAML it reads at session start, independent of model or frontend. Context compounds instead of restarting. MIT.

Install
npx -y skills add bks-lab/open-bridge --skill meeting-transcription

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 8 stars8 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Operates and manages a context-aware meeting-transcription pipeline (2-track or single-mix recording → whisper.cpp large-v3 + pyannote diarization on a worker host → voice-matched speaker names → naked transcript delivered to /debrief; the summary is made later by the in-session /debrief, never by the worker). The reference implementation of the transcription-worker contract (docs/transcription-worker.md). Use this skill WHENEVER the user wants to transcribe a meeting, set up or change a transcription context/folder, add or re-train a speaker voice, reprocess a recording, extend the pipeline, or troubleshoot it — even if they don't name the pipeline explicitly. Triggers: "transcribe a meeting", "transcription folder", "new transcription context", "add a speaker", "train a voice", "voice library", "speaker recognition", "speaker diarization", "who said what", "reprocess recording", "transcribe pipeline", "update the whisper model". Also use it to answer "how does my transcription system work" — it is the source of truth for that system.

SKILL.md

13.6 KB, ~3.0k tokens by cl100k_base, as published. Nobody here has run it

Meeting Transcription Pipeline

A pipeline that turns meeting recordings into clean, structured Markdown transcripts with named speakers. It is context-aware: each context (e.g. main, customer-x) has its own voice library, language default, and output routing, so the same system serves internal standups and customer calls in different languages without reconfiguration.

This skill is both the knowledge base (how the system works) and the operations manual (how to change it). The canonical scripts live in scripts/ here and are deployed to the worker host's ~/transcribe-pipeline/. It is the reference implementation of the bring-your-own-worker contract in docs/transcription-worker.md/debrief talks to it only through scripts/debrief_sync.sh (pull / push).

Configuration — the yaml wiring

Three config surfaces, same pattern as every other capability:

1. bridge-config.yaml — the integration block (is the capability on, which script, which contexts — registration + routing):

integrations:
  transcription:
    enabled: true
    sync_script: "skills/meeting-transcription/scripts/debrief_sync.sh"
    default_context: main        # context for audio handed off without an explicit one
    contexts:
      main:                      # → workflow/contexts/main.yaml
        imports: work/imports    # where this context's transcripts land on pull

BRIDGE_IMPORTS / TRANSCRIBE_CONTEXTS env-override the imports dir + context list. /debrief degrades gracefully to its manual path when the block is absent (see the contract doc).

2. infra/transcriptions/topology.yaml — placement (WHERE the pipeline runs):

mode: remote                   # local | remote — THE topology switch (env TRANSCRIBE_MODE overrides)
worker:                        # consulted only when mode == remote
  host: worker-host            # SSH/Tailscale alias — see infra/remotes/
  launchd_label: com.openbridge.transcribe-worker
# local:                       # consulted only when mode == local; all keys optional
#   inbox_dir:       ~/transcribe-inbox        # defaults = the worker's own conventions
#   transcripts_dir: ~/Transcripts
#   library_dir:     ~/transcribe-pipeline/speaker-library
#   contexts_dir:    ~/transcribe-pipeline/contexts

Resolution: TRANSCRIBE_MODE / TRANSCRIBE_WORKER env > topology.yaml > inferred (a worker host resolves ⇒ remote, else local). remote runs every op over ssh+rsync; local runs plain filesystem cp/mv with no SSH (the compute stack is still required). An unknown mode fails loud. Schema + guide: infra/transcriptions/README.md.

3. workflow/contexts/<ctx>.yaml — per-context settings. A context "participates in transcription" iff it carries an integrations.transcription: block (schema: IntegrationTranscription in workflow/contexts/_schema.yaml):

integrations:
  transcription:
    language: auto        # de | en | auto (multi-window vote)
    library: main         # → speaker-library/<library>/*.npy on the worker
    output: main          # → ~/Transcripts/<output>/ on the worker
    notify: false         # completion ping (e.g. iMessage on macOS)
    # mic_speaker: Alice  # display name for the dual-track mic channel (default "Me")

The skill does not maintain its own context directory — two files joined-by-slug drift silently. Discovery rule (codified — run this whenever you need to know what contexts exist):

for f in workflow/contexts/*.yaml:
    data = yaml.safe_load(f)
    if data.get("integrations", {}).get("transcription"):
        ctx = data["id"]                              # slug, e.g. "main"
        settings = data["integrations"]["transcription"]
        # → this context is live; use settings

The worker doesn't parse the bridge yaml directly (its cfg() helper is awk-based and can't read nested keys). The deploy step closes that gap: scripts/extract_runtime_contexts.py reads the bridge yamls, flattens each integrations.transcription block into a flat runtime yaml per context (language, library, output, notify, mic_speaker), and rsyncs the result to ~/transcribe-pipeline/contexts/. The worker keeps its simple parser; the bridge keeps a single source of truth.

The 30-second model

capture machine (optional)     worker host                        Claude
──────────────────────────     ───────────                        ──────
2-track recorder or any  ──►   ffmpeg split (mic-L / meeting-R)
mixed recording                whisper.cpp large-v3 (Metal GPU)    ASR
~/Recordings/meetings/<ctx>/   + pyannote diarize on MPS (+embeddings)
        │                              │
launchd transcribe-bundler.sh  speaker_naming.py ◄── speaker-library/<ctx>/*.npy
   rsync per context                   │
        ▼                      merge_transcripts.py → transcript-raw.md
worker:~/transcribe-inbox/<ctx>/       │   (the NAKED transcript = worker output)
launchd transcribe-worker.sh   deliver ~/Transcripts/<ctx>/<ts>.md
                                       │
                                       ▼   NO summary on the worker
                          in-session /debrief → context-aware summary + tasks

Key idea — identity comes from voice, not text. Speakers are matched by pyannote voice-embedding (cosine ≥ 0.60) against a per-context library, so "Alice" is always labelled Alice even when Whisper mishears her name.

Second key idea — transcription is mechanical, interpretation is contextual. The worker produces ONLY the naked transcript (ASR + diarization + voice-match — no bridge context needed). The summary/tasks are made by the in-session /debrief, which has the bridge loaded (name conventions, ecosystem, board, open issues, contexts, prior meetings). A headless worker-side summarizer was removed for being context-blind: it distorted names and significance.

When to read which reference

This SKILL.md is the map. For anything beyond the quick operations below, open the matching reference — they hold the detail so this file stays scannable.

You need to…Read
Understand data flow, file layout, every script's rolereferences/architecture.md
Add a context, add/re-train a speaker, reprocess, extend the pipelinereferences/operations.md
Know what you need first (worker / capture / bridge prerequisites)references/deployment.md § Prerequisites
Provision a worker host from scratch (venv, HF token, launchd)references/deployment.md
Fix diarization bleed, OOM, language misdetect, delivery failuresreferences/troubleshooting.md

Core concepts

  • Context = the inbox subfolder a recording lands in. Defined by the integrations.transcription block of workflow/contexts/<name>.yaml (see Configuration above). To add a context: add the yaml, re-deploy.
  • Voice library = speaker-library/<context>/<name>.npy — 256-dim pyannote embeddings, one file per known speaker (can stack multiple samples). Bootstrapped once per speaker, then reused forever.
  • Bilingual = Whisper auto-detects language (or the context forces it); the transcript frontmatter records it; the summary prompt (prompts/meeting-summary-{de,en}.md) is chosen by /debrief to match.
  • Summary = NOT here. The worker does no summarizing — it delivers the naked transcript only. Summary + task-extraction happen in the in-session /debrief. summarize.py survives only as a manual headless fallback; prompts/meeting-summary-{de,en}.md is the /debrief summary template. The mechanical scripts/anchor_transcript.py (per-utterance anchors + .index.tsv, makes a transcript addressable) is owned here but invoked by /debrief's gold path; the interpretive evidence-linking stays in-session.
  • Engine = hybrid (GPU). ASR runs on whisper.cpp large-v3 (Metal) via asr_whispercpp.py; diarization + the 256-d embeddings run on pyannote/MPS via diarize_assign.py — the same embedding space the library was built in, so libraries keep matching. A CPU-only fallback stays one env var away: TRANSCRIBE_ENGINE=whisperx. Rationale + measurements: references/architecture.md § Engine.

Quick operations

Most requests map to a playbook in references/operations.md. The headlines:

Transcribe a meeting — drop the recording into the context's inbox; the worker auto-runs. Manual: <worker>:~/transcribe-inbox/<ctx>/<ts>/meeting.mp3

  • touch .READY. No 2-track? A mono/stereo-mix file still works (diarization separates by voice; set tracks: single in the manifest — the sync script's push does this automatically). Always confirm the right context first.

Add a context (bridge-side YAML + remote dirs + recording dir):

  1. Add workflow/contexts/<name>.yaml (copy from _template.yaml — fill schema_version, scope, id, and an integrations.transcription block). Validate: check-jsonschema --schemafile workflow/contexts/_schema.yaml workflow/contexts/<name>.yaml.
  2. Bootstrap the remote dirs + recording folder: bash skills/meeting-transcription/scripts/add_context.sh <name>.
  3. Deploy: extract + rsync (see references/deployment.md § Redeploy).
  4. Point your recorder at ~/Recordings/meetings/<name>/ (capture machine).

Add / re-train a speaker — after a meeting is diarized, show the user who each cluster is, then persist the voiceprint:

python bin/speaker_idcard.py --json <inbox>/<ctx>/<ts>/teams_out/teams.json
python bin/apply_speaker_names.py --json <that.json> --out teams-named.json \
   --map "SPEAKER_00=Alice,SPEAKER_01=Bob" \
   --library speaker-library/<ctx> --save-embeddings

Stacking more samples over time sharpens recognition.

Reprocess — delete the bundle's .PROCESSED flag and touch .READY, or re-run the steps manually. Cached teams.json means re-naming is cheap (no re-transcription). See operations.md § Reprocess.

Re-summarize only (manual fallback, e.g. after improving a prompt): python bin/summarize.py --raw <bundle>/transcript-raw.md --out <bundle>/transcript.md --prompt-dir prompts

Bridge to /debriefscripts/debrief_sync.sh implements the worker contract (docs/transcription-worker.md):

  • debrief_sync.sh pull — fetch finished transcripts into the bridge imports dir (prefixed <ctx>-…) where /debrief Phase 1 finds them.
  • debrief_sync.sh push <audio> [ctx] — hand an audio file to the pipeline; the transcript arrives async and is collected on the next pull. /debrief runs pull at the start of Find and push for any audio without a transcript. Run it from the machine that can SSH into the worker.

Back up / sync voiceprintsdebrief_sync.sh voiceprints pull syncs the per-context speaker-library/*.npy from the worker into the bridge under identity/voiceprints/<ctx>/; voiceprints push restores them onto a fresh worker. These are biometric embeddings (GDPR Art. 9), so identity/voiceprints/ is user data — it never promotes upstream. Git tracking is opt-in per context via your .gitignore; an instance handling customer meetings should route customer voiceprints to that customer's own repo rather than track them here. An optional weekly launchd job keeps the backup fresh (scripts/voiceprint_backup.sh + com.openbridge.voiceprint-backup.plist).

For anything structural (new pipeline stage, model swap, threshold tuning), read references/operations.md § Extend and references/troubleshooting.md — and explain the change to the user before deploying, since the worker runs unattended via launchd.

Hard rules

  • Voice libraries are per-context. Never match one context's meeting against another context's voices — that's the whole point of the split. Only the recording user legitimately appears in multiple libraries.
  • HF token lives in the worker's keychain (service hf-token-pyannote) or ~/.config/open-bridge/hf-token (chmod 600). Keychain writes over SSH fail (audit session) — use the file fallback when provisioning remotely.
  • The worker runs unattended — validate script changes (bash -n, a manual bundle run) before relying on the launchd trigger.
  • Customer transcripts route to the customer's repo at the /debrief stage; this pipeline only produces the Markdown.
  • Voiceprints are biometric data — never commit them to a shared repo, never promote them upstream.

Gives 0 of the 12 instructions most video audio skills give in ~3.0k tokens

Counted across 621 of the 795 authors here whose files we hold, read 2026-08-06

  • read individual rule files for detailed explanationsin 21 of 621, across 9 files
  • Use WAV PCM 16kHz mono audio formatin 13 of 621, across 4 files
  • render final videoin 13 of 621, across 6 files
  • use this skill when dealing with Remotion codein 11 of 621, across 4 files
  • save generated audio to a WAV filein 11 of 621, across 4 files
  • handle conversion errors gracefullyin 10 of 621, across 6 files
  • add captions to videos alwaysin 10 of 621, across 4 files
  • generate music from text descriptions using MusicGenin 9 of 621, across 2 files
  • do not skip pipeline layersin 9 of 621, across 3 files
  • do not make one tool do everythingin 9 of 621, across 3 files
  • never ask the user to paste their full API keyin 9 of 621, across 3 files
  • use azure document intelligence for complex pdfsin 9 of 621, across 4 files

Said here and by no other author read

  • match speakers by voice embedding
  • produce only naked transcripts on worker
  • always confirm correct context first
  • validate context yaml against schema
  • bootstrap remote dirs after adding context
  • explain structural changes before deploying

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.