TapScribe
Local transcription recorder and operator dashboard. TapScribe records one WAV per utterance per speaker over a WebSocket, runs Whisper / Voxtral / Parakeet batch transcription on demand, and supervises a WhisperLiveKit child process for live captions. Nothing leaves the machine.
Audio arrives via a bridge — usually a browser extension that taps the
meeting platform's audio tracks and streams raw PCM to the /tap WebSocket.
The included bridges/spacialchat-bridge/ targets spatial.chat; see
bridges/README.md for the wire protocol.
Beyond record + transcribe: a hallucination filter (substring / exact: /
re: rules; suppressed segments kept in an audit array), silence-stripping
(trimmed copies in <session>/stripped/, originals untouched), summarization
(bundled local model, operator CLI, or an OpenAI-compatible API), a People
registry (cross-session speaker identity → display name, with merge/detach),
and an end-of-meeting pipeline (strip → transcribe → summarize as one job a
Bridge can trigger and poll with the tap token — no operator in the loop).
CONTEXT.md has the domain model.
Dashboard
One operator console at / — the "Stages" UI. A slim left spine navigates the
global views (Taps · Sessions · People · Settings) and the per-session journey
(Capture → Recordings → Transcript → Summary); the active-taps rail follows you
across views. Live captions stream in Capture; silence-stripping and the
per-WAV files live in Recordings; the ▶ transcribe range button, the
meeting-languages declaration (ADR-0011), and the merged transcript live in
Transcript; the live and batch engine pickers live in Settings.
Captured live by the browser E2E test: the Apollo 11 fixture through the
bridge and a real faster-whisper tiny.en. Bigger models clean up the
self-flagged low-confidence output considerably.
Quick start (macOS / Linux)
bash start.sh # localhost only
bash start.sh --lan # bind 0.0.0.0
The script finds Python 3.12+, creates .venv, base-installs the package, and
launches the recorder on port 8001. Pick transcription models in the browser at
http://localhost:8001/setup (/ redirects there until a model is installed);
/setup doubles as the manage-models surface. Other flags: --non-interactive
(headless — install the saved/default model selection without the browser),
--no-mlx (skip MLX on Apple Silicon; live and batch both use MLX there by
default), --auto-live (boot with live captions running), --tls, --no-auth
(dev only).
Live captions are off by default: start whisperlivekit-server from the
dashboard. The recorder supervises it as a child on an ephemeral internal port
(pin one with SX_PORT_WLK); child logs are prefixed [wlk]. Ctrl+C stops the
recorder and any child.
On first run two secrets are generated and printed:
- a dashboard password for HTTP Basic auth, persisted to
.auth-password; - a
/tapbearer token for bridges, persisted to.tap-token— paste it into the bridge popup along with host and port.
Rotate with .venv/bin/tapscribe --rotate-password / --rotate-tap-token.
start.sh --tls serves https:// + wss:// with a self-signed cert generated
on first boot (.tapscribe-cert.pem, .tapscribe-key.pem) and reused after;
to supply your own, run tapscribe directly with --tls --cert <path> --key <path> (recorder flags, not start.sh flags).
Windows
Windows Bundle (no Python needed)
Download TapScribe-Setup-win-x64.exe from the
latest release and run
it. Per-user install (no admin prompt), carries its own interpreter; a tray
icon starts the dashboard and its Copy password item gives you the
generated login. The Bundle is unsigned, so SmartScreen warns — click More
info → Run anyway. Program files land in %LOCALAPPDATA%\Programs\TapScribe;
recordings, transcripts and settings live in %USERPROFILE%\TapScribe and
survive uninstall; model weights cache in %USERPROFILE%\.cache\huggingface.
See packaging/README.md and
ADR-0015.
From a checkout (developers)
.\start.ps1 # flags mirror start.sh: -Lan, -NoMlx, -AutoLive, -Tls, -NonInteractive
Other installs
- PyPI:
pip install tapscribe, thentapscribe. Models still install via/setup. - Docker (CPU-only):
docker run --rm -it -p 8001:8001 -v "$PWD/data:/data" ghcr.io/vortiago/tapscribe:latest
Configuration
Editable config files live under config/ and are re-read on every job; all
are editable from the dashboard's Settings view (further knobs — chunk sizes,
timeouts, model idle TTL — live under Settings → Advanced).
| File | Shapes |
|---|---|
config/prompt.txt / live-prompt.txt |
Batch initial_prompt / live --init-prompt (independent). Prose under ~150 words. |
config/hotwords.txt |
Batch hotwords — proper nouns; faster-whisper only. |
config/hallucinations.txt |
Suppression rules: substring, exact:, or re:. Ships with common YouTube-trained Whisper hallucinations. |
config/batch-model.txt / live-model.txt |
Default batch / live model ids. |
config/languages.txt |
Candidate languages (ADR-0010); default da,no,en. |
config/summarizer.json |
Default summarizer (source, command/model/base_url, prompt; api_key write-only). |
Architecture
One backend, one supervised child, N bridges. Audio flows in over WebSocket; captions and recordings come out.
flowchart LR
subgraph Meeting["Meeting platform (e.g. spatial.chat)"]
Bridge["Bridge<br/>(browser extension<br/>or native helper)"]
end
subgraph Host["TapScribe host"]
Backend["TapScribe backend<br/>FastAPI :8001<br/>/tap · /api · dashboard"]
WLK["whisperlivekit-server<br/>(supervised child, internal port)"]
WAVs[("recordings/<br/><session>/*.wav")]
end
Operator["Operator browser<br/>(dashboard)"]
Bridge -- "PCM 16k mono<br/>over WS /tap" --> Backend
Backend -- "forwards PCM" --> WLK
WLK -- "settled live captions" --> Backend
Backend -- "one WAV per utterance" --> WAVs
Operator <-- "HTTPS (500 ms /api/state poll)" --> Backend
One /tap WebSocket = one utterance. Each PCM frame is tee'd: appended to the
per-utterance WAV on disk and relayed to the WhisperLiveKit child for live
captions. The two sinks are independent — if WhisperLiveKit is down, recording
still works. Bridges never talk to the child directly.
Backends
| Family | Models | Backend | Languages | Notes |
|---|---|---|---|---|
| Whisper | tiny(.en)/base(.en)/small(.en)/medium(.en), large-v3, large-v3-turbo |
mlx-whisper (AS) / faster-whisper | English-only suffixes; else multilingual | large-v3-turbo is the default generalist (ADR-0010). |
| NB-Whisper | nb-whisper-tiny/base/small/medium/large |
faster-whisper on CT2 weights | Norwegian | Pulled from NbAiLab/nb-whisper-*/ct2/. No MLX. |
| Voxtral | voxtral-mini |
mlx-voxtral (AS) / HF transformers | EN/ES/FR/PT/HI/DE/NL/IT | Batch-only. First load downloads ~6 GB. |
| Parakeet | parakeet-tdt-0.6b-v3 |
parakeet-mlx (AS) / HF transformers | 25 EU languages, no Norwegian | Batch-only; replaced Canary (ADR-0006). |
| Moonshine | moonshine-tiny/base |
mlx-audio (AS) / ONNX-CPU | English | Live-only low-latency captions. Extras [moonshine-mlx] / [moonshine-cpu]. |
Tests
pip install -e ".[dev]"
python -m pytest -q
Unit + route tests (backends stubbed, under 20 s), an HTTP pipeline E2E over
real /tap WebSockets, a real-Whisper E2E on committed CC-licensed fixtures,
a Playwright dashboard-UI E2E, and a headed bridge-extension E2E. See
CONTRIBUTING.md for how to run each layer. GitHub Actions
runs the suite and ruff on every push and PR across Python 3.12-3.14 on
Ubuntu, macOS, and Windows.
License
MIT. See LICENSE.
Metadata
Release files for tapscribe 1.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| tapscribe-1.3.0.tar.gz | 3.2 MB | With provenance | Details for tapscribe-1.3.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| tapscribe-1.3.0-py3-none-any.whl | Python 3 | none | any | Details for tapscribe-1.3.0-py3-none-any.whl |
Total release size: 6.0 MB
Release files / tapscribe-1.3.0.tar.gz
| Download URL | tapscribe-1.3.0.tar.gz |
|---|---|
| Size | 3.2 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4d7989248732161a447c9e1019fce32cc45245287e7a5779a74abe6647685f08
|
|
BLAKE2b-256 checksum How to use checksums |
bd2078729bf0e69d4a7a69f047807bfc987d8311e53d59695c3ec1253a783914
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 27, 2026.
Transparency logRelease files / tapscribe-1.3.0-py3-none-any.whl
| Download URL | tapscribe-1.3.0-py3-none-any.whl |
|---|---|
| Size | 2.8 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
442465590870eb2f4393fee63d39b730ac28a65bb4b2381378e3f8637fa7ad88
|
|
BLAKE2b-256 checksum How to use checksums |
52fc3cacbf660c0e6b2961ba18455359ae6e99e91477c2fdf9ddc8cf43b44ea1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 27, 2026.
Transparency logSecurity for tapscribe 1.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for tapscribe-1.3.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 27, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.