Back to dollama.net

Capabilities

The network does more than chat completion. Transcribe audio with dollama transcribe, generate text embeddings with dollama embed — routed to nodes that advertise the capability, not to whichever model happens to be loaded.

Work that isn't chat completion

Most of dollama routes an LLM prompt to a node running a worker, planner, or helper model. Capabilities are a separate axis. A node can advertise that it can transcribe audio or produce embedding vectors, independently of which LLM role it was assigned — and the relay keeps a distinct pool for each, so a transcription request is matched against nodes that can actually transcribe.

Two capabilities are documented here: audio_stt (speech-to-text) and embeddings. Both follow the same shape — your CLI sends the request, the relay picks a node from that capability's pool, the node does the work and streams the result back. As everywhere else on dollama, the relay stays content-free: your audio and your text are pulled by the serving node over the content tunnel, never stored on the relay.

You can see what the live network currently offers — pool depth, benchmark medians, and each capability's wire contract — under the capabilities key of GET /v1/network/models.

Transcribe an audio clip

dollama transcribe <audio-file>

Sends a local audio file to a node advertising audio_stt and prints the transcript as JSON. Per-word timestamps are on by default. Progress streams back as the transcription runs, so a long clip reports partial text rather than sitting silent.

dollama transcribe recording.wav
dollama transcribe --language en --verbatim voicemail.ogg
dollama transcribe clip.wav --output transcript.json
FlagTypeDefaultDescription
--languagestringauto-detectISO-639-1 hint (e.g. en). Omit to let the model detect the language.
--verbatimboolfalseRetain fillers and disfluencies (“um”, “uh”). Routes to a filler-preserving model with more precise timestamps.
--no-word-timestampsboolfalseOmit per-word start/end times. Word timestamps are on unless you turn them off.
--initial-promptstring""Vocabulary or glossary bias for domain terms — names, jargon, product words the model would otherwise mishear.
--modelstring(network default)Explicit STT model. Omit unless you have a reason.
--publicboolfalseAllow routing to public volunteer nodes. Off by default — see Routing & privacy.
--outputstringstdoutWrite the JSON result to this file instead of stdout.
--relay-urlstring(config)Relay URL override.
--tokenstring(config)Auth token override.

Output

{"text", "language", "words", "duration_s"}. Each entry in words carries word, start, and end in seconds — enough to build subtitles, seek to a phrase, or align a transcript against the source audio.

{
  "text": "the quick brown fox",
  "language": "en",
  "duration_s": 3.0,
  "words": [
    { "word": "the",   "start": 0.00, "end": 0.20 },
    { "word": "quick", "start": 0.20, "end": 0.55 }
  ]
}

Word-level probability is part of the schema but the backend does not populate it in practice, so treat it as absent rather than as a confidence score.

Getting better transcripts

Use --initial-prompt for domain vocabulary. It biases the decoder toward words it would otherwise guess wrong — the single highest-leverage flag on this command:

dollama transcribe standup.wav \
  --initial-prompt "dollama, Ollama, Qwen, relay, OET, Fly.io, Neon"

Pass --language when you know it. Auto-detection costs accuracy on short or noisy clips. Use --verbatim only when hesitations matter — for meeting notes or captions the default reads far better.

Serving speech-to-text

STT runs on Speaches, an OpenAI-compatible faster-whisper server that dollama installs and manages alongside Ollama. dollama setup offers to install it; you can also add it later:

dollama audio-install          # install and start Speaches
dollama audio-probe            # check whether this machine can host it
dollama benchmark --stt        # measure RTF and WER, cache the result
dollama benchmark --stt --sweep  # compare whisper model sizes on your hardware

The install is CPU-capable and gated only on disk space, not on VRAM — a machine too small to serve LLM inference can still contribute transcription, which is why setup recommends it more strongly on client-only hardware. You can also enable, benchmark, and compare models from the Settings → Speech-to-Text card in the local dashboard.

Pool thresholds

Your benchmark decides whether the node joins the audio_stt pool at all:

AxisMeaningGate
rtfReal-time factor — processing time divided by audio duration. Lower is better; below 1.0 means faster than real time.≤ 1.0
werWord error rate against reference transcripts, as a percentage.≤ 25%

WER needs a real speech corpus with reference transcripts to measure. Set stt_corpus_dir in your config to a folder of clip.wav / clip.txt pairs to calibrate it; without one, the benchmark measures RTF against a synthetic probe and reports WER as uncalibrated.

Turn text into vectors

dollama embed [text...]

Sends one or more texts to a node advertising embeddings and prints the vectors as JSON. Built for scripts, RAG indexing pipelines, and one-off lookups — not an interactive session. It lets you build retrieval on dollama without a local GPU budget for an embedding model.

dollama embed "what is the capital of France?"

# A batch in one round trip — measurably faster per item than looping.
dollama embed "first chunk" "second chunk" "third chunk"
dollama embed --file chunks.txt          # one text per non-empty line
cat chunks.txt | dollama embed           # same, from stdin
FlagTypeDefaultDescription
--filestring""Read texts from this file, one per non-empty line, instead of args or stdin.
--no-truncateboolfalseError instead of truncating inputs that exceed the model's context.
--modelstring(network default)Embedding model override. The network sanctions one model so every vector is comparable — see below.
--outputstringstdoutWrite the JSON result to this file instead of stdout.
--relay-urlstring(config)Relay URL override.
--tokenstring(config)Auth token override.

Output

{"model", "dims", "embeddings", "usage"}. embeddings is one float array per input text, in the same order as the inputs, and dims is the vector width.

{
  "model": "qwen3-embedding:0.6b",
  "dims": 1024,
  "embeddings": [[0.0123, -0.0456, "…"]],
  "usage": { "prompt_tokens": 8 }
}

Batch rather than loop. Sending N texts in one call is one network round trip and one backend call; sending them one at a time is N of each. A single request accepts up to 512 texts or 8 MiB of text, whichever comes first.

The network deliberately sanctions a single embedding model rather than a hot-swappable set. Vectors from different models are not comparable, so one model network-wide is what makes an index built today still searchable tomorrow — and it keeps a small embedding model resident alongside a node's LLM role instead of thrashing them against each other.

Serving embeddings

Embeddings need no extra host process — Ollama already serves embedding models natively, so your node's existing Ollama is the backend. dollama setup offers to pull the sanctioned model and benchmark it; the Settings → Embeddings card in the dashboard does the same at any time.

dollama benchmark --embeddings          # measure throughput and latency
dollama benchmark --embeddings --sweep  # compare embedding models on your hardware

The model is small enough (0.6B-class) to stay loaded next to a worker or helper model on most GPUs, and is negligible on a CPU-only box — so this is a real way for modest hardware to contribute.

Pool thresholds

AxisMeaningGate
embed_tok_per_secInput tokens embedded per second on a single-item call.≥ 20
p95_latency_ms_single95th-percentile latency for a single-item request.≤ 2000 ms
batch_speedupBatch throughput divided by single-item throughput.informational

batch_speedup never gates membership — it exists so the fleet-wide benchmark surface can show how much batching actually helps. A node below either real gate simply doesn't join the pool; nothing else about it changes.

Where your audio and text actually go

Speech-to-Text is private by default

Recorded speech is treated as more sensitive than a chat prompt, so dollama transcribe routes to your own nodes and your groups' nodes only, and fails closed: if none is available the request errors rather than falling through to a public volunteer. Pass --public to deliberately opt into the public pool.

This is enforced in two independent places — the relay's node picker and again in the claim itself — so a routing bug in one cannot leak a private clip through the other.

Embeddings follow your mode

dollama embed uses the same privacy mode as the rest of your session (dollama private / group / network). If you are indexing sensitive material, run in private or group mode so the work stays on machines you or your group control.

The relay never stores your content

Audio clips travel as a content reference the serving node pulls over the reverse content tunnel; the relay routes and streams but holds nothing. Embedding inputs ride inline with the request for latency reasons, and are likewise never persisted relay-side. See Docs for the full data-flow picture.

What these don't do yet

Being straight about the edges, so you don't build against something that isn't there:

Not availableWhat to do instead
OpenAI-compatible /v1/audio/transcriptions or /v1/embeddings REST endpoints Use the CLI, or send a request to POST /v1/messages naming the capability. See the API Reference.
Microphone capture and voice-activity detection Record with any tool you like and pass the file. dollama has no client-side capture pipeline.
Streaming audio in — live dictation from an open mic Send whole clips. Transcription progress streams back out, but the input is a complete file; clips are capped at 5 minutes.
Text-to-speech / read-aloud Not implemented. Designed, not built.
Speaker diarization (“who said what”) Not implemented.
Vector storage or search dollama embed returns vectors; storing and searching them is yours. Any vector store works.

Both capabilities depend on nodes choosing to advertise them. If a request fails with no node available, check the capabilities key of GET /v1/network/models for the current pool depth — and consider serving it yourself.