nika:tts_generate
Media
Tool family from the canonical registry.
invoke
Call this builtin through the invoke verb.
Read this contract
This reference preserves the specification at the revision linked below. Source examples are fragments: their surrounding tasks, inputs and permissions are not supplied here. Consult engine status andnika catalog --tools --json for the installed implementation; a registry declaration is not a runtime qualification.
Usage and behavior
illustration
17-tts-self
(provider: mock · a real WAV · offline). Real speech with no key and no
network · provider: system (the host’s own synthesizer, below).
The image family’s contract, applied to audio: ONE audio file lands under
output_dir: (permit-gated per final path BEFORE I/O · atomic write ·
content-hash-named {stem}-{provider}-{model}-{sha8}.{ext} so identical
re-runs are idempotent), the output carries { provider, model, voice, created_at, endpoint_host, audio: { path, filename, format, mime_type, size_bytes, sha256, duration_ms }, cost_usd, warnings, manifest_path, output_dir } (plus cost_basis and cost_as_of beside a non-null
cost_usd, as image_generate · catalog_rate_x_characters: the
engine’s dated catalog rate per character × the characters the request
sent, the text as trimmed · a provider’s own exact report stays
provider_reported; plus cost_unpriced when the engine knows why
cost_usd is null · system) — audio bytes NEVER ride outputs, and a
sidecar provenance manifest (manifest: true default) echoes the resolved
request.
Validation (engine MUST) · the payload is sniffed (WAV
RIFF…WAVE ·
MP3 ID3/frame-sync) — a non-audio payload is a hard -007; WAV
duration_ms is exact header math over the bytes actually PRESENT: a
data chunk declaring more than the payload carries (a streamed WAV’s
0xFFFFFFFF placeholder size) counts only the bytes present, so a
streamed narration never reports a 24-hour duration. MP3 duration is
honestly null (never a guess). Empty payloads are -004.
The system provider (keyless · offline · engine-run). The engine
starts the host’s own synthesizer ITSELF, as part of the builtin: macOS
/usr/bin/say (16-bit PCM WAV · 22050 Hz · written to an engine scratch
file, never a workflow path), Linux espeak-ng --stdout found in an
absolute directory of the engine’s PATH (never a relative entry). The
text rides the program’s standard input, never its argument vector, and is
spoken as TEXT, never synthesizer markup: both programs read [[ as the
start of markup (say’s embedded commands such as [[volm 0]] ·
espeak-ng’s phonemes), so the engine breaks every [[ with a space
before the text reaches them. The audio is capped at 64 MiB (-003 ·
never transient · measured before it is read). It is never the
workflow’s exec:: no permits.exec is required or consulted, the program is fixed by the engine (never
workflow data), and the audio still lands under output_dir: through
permits.fs.write like every provider. A static checker names the
program the call will start; the journal records the start as the
builtin’s own effect (a permit_checked frame · plane: builtin · spec
17), never as an exec: decision. On any other operating system, or
when the program is absent, the call fails -002 naming what is missing
— never a silent fallback to another provider. A non-zero exit is -003
(never transient · the synthesizer’s message is carried). Cost · local
compute is unpriced, never free: cost_usd is null, the output names
the reason (cost_unpriced: local_model), and the run reports the task
unpriced on its journal frame the same way · never a priced 0.
Security (engine MUST) · endpoints are engine-fixed constants (the
local base URL is engine config at the composition root — the same
sanction as image_generate and infer:) · keys are engine-configured
(OPENAI_API_KEY · ELEVENLABS_API_KEY · NIKA_TTS_LOCAL_API_KEY or
the NIKA_-prefixed forms), never workflow args, never logged · a
verbose local server reflecting the Bearer into an error body MUST be
scrubbed (the image family’s rule).
Throws · NIKA-BUILTIN-TTS_GENERATE-001 invalid arguments
(validation_error) · -002 provider unavailable (a missing key · an
unwired plane · no system synthesizer on this host · validation_error) ·
-003 request failed (network_error · transient: true for
5xx/408/429 + timeout/connection) · -004 empty audio (tool_error) ·
-005 content policy (security_error · never transient) · -006 save
failed (tool_error) · -007 payload validation (tool_error) — the
image twin’s category ladder, code for code.
Related concepts
Arguments
Pass the values required by the tool contract.
Permissions
Understand authority before granting effects.
Errors and recovery
Read diagnostics and choose a recovery policy.
Workflow templates
Put the fragment inside a complete workflow.
Contract provenance
Read the pinned specification · Canonical registry. Tool identity:nika:tts_generate. Specification revision: 5cd95cd25c0f.
Documentation
Guides, reference contracts and working examples.
Language spec
the nine-key envelope, Apache-2.0. The contract these docs explain.
Engine source
Rust, AGPL-3.0-or-later. Every commit public.
TypeScript SDK
Use one typed lifecycle locally or against authenticated nika serve HTTP.
Editor extension
The editor extension, frozen at 0.120 and not qualified with 0.124: use
nika lsp and the JSON Schema.Homebrew tap
brew install supernovae-st/tap/nika for the latest tagged CLI release.SuperNovae
The Paris studio crafting Nika. 🦋