Skip to main content
Builtins catalog / 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 and nika catalog --tools --json for the installed implementation; a registry declaration is not a runtime qualification.

Usage and behavior

illustration
Teaching shape · 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.

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. 🦋