output_dir, optional. absent, the text lands beside the recording as it always has — that is what a person right-clicking a memo wants and it is not changing. given, the transcript goes there instead, and the directory is created if it does not exist. for callers that are not a person clicking a file. a commander keeps its results in its own directory, and the alternative was making every commander move the file afterwards: a step in the loop forever, plus a window where the file sits in the folder being watched. marked `hidden` so the file browser neither shows it nor counts it as something to ask about — without that, declaring it turned a direct right-click run back into a modal with a field nobody clicking a file has an answer for.
Transcribe
Officer's speech-to-text, talking to a self-hosted whisper.cpp server.
Transcribe does not run Whisper and ships no model. You point it at a whisper.cpp /inference server
you already run and it forwards to it, tuned for one person talking into a phone: detect the spoken
language, then transcribe faithfully in it — never translated, never guessed at in English when the
audio is not.
What you get
POST /api/transcribe/transcribe— send an audio file, get back its text and the language Whisper detected. Two-pass under the hood (detect, then transcribe in that language) so a low-confidence guess never quietly defaults to English.- Conversations come back as conversations. Nobody declares what a recording is — a probe on the
diarization worker runs alongside every transcription and finds out. Solo dictation returns as
paragraphs, exactly as before; a recording with several voices returns speaker-labeled
(
Speaker 1: …) withconversation: trueand a speaker count. The worker is optional: without it, or if it fails mid-request, everything still transcribes — just never labeled. See~/dockers/torch-workerfor the worker itself. - Fair queueing for a multi-user server. Transcription and diarization each run one job at a time behind their own queue, in arrival order — and on different hardware, so the conversation probe costs a solo memo nothing.
- A file-browser task. Right-click an
.mp3,.wavor.m4aand transcribe it without a model turn — the task is a plain script that calls this plugin's own route and files the result next to the original. - A skill, so an agent asked to transcribe something knows the route, the shape, and what to say when nothing is configured, without being told.
What you need
A whisper.cpp server you already run, reachable from this machine, answering POST /inference —
the same container the platform used to talk to directly. Nothing else. No system packages, no host
binaries; the sidecar reaches it with fetch.
Setup
PUT /api/transcribe/config
{ "url": "http://192.168.1.50:64201" }
Validated against the server before it is stored — a wrong URL is a 400 with the reason, not a saved value that fails on the first real transcription.
What this plugin deliberately does not have
- No dashboard route, no dock tile. There is nothing to look at — this is reached through the file
browser's task menu and by an agent that has read the skill, not through a screen. Shipping no
web/is a supported shape, not an oversight. - No streaming. One file in, one answer back. If you want a live microphone, that is a different feature built on top of this one, not something this plugin does today.
- No translation. It transcribes in whatever language was spoken. Whisper's own translate mode is English-only, so honouring "translate into <language>" for anything else would mean silently handing back a rough English rendering of, say, Portuguese audio — worse than refusing.