Isimud

Haz que tu agente te hable (solo OSX)

Documentación

isimud

Crates.io Version CI Crates.io Downloads License Discord Buymecoffee

isimud es una app de la barra de menús de macOS y un servidor MCP de HTTP transmisible que permite hablar a los agentes de IA. Un agente envía texto a una herramienta MCP; isimud resuelve una voz con nombre, sintetiza el habla mediante Apple, OpenAI o Google, y luego la reproduce a través de una única cola de habla serializada.

isimud es la contraparte de texto a voz de muninn, que convierte el habla en texto para los agentes.

Usa isimud cuando quieras:

  • Una app local de bandeja de macOS que pulse mientras un agente está hablando.
  • Un servidor MCP sin interfaz gráfica para uso mediante scripts o en segundo plano.
  • Texto a voz local primero, con proveedores en la nube opcionales con tu propia clave.
  • Voces con nombre que ocultan los ID de voz específicos del proveedor a los agentes.
  • Cola, cancelación, estado y notificaciones del ciclo de vida del habla a través de MCP.

Inicio rápido

Completa esta ruta para ejecutar isimud con el proveedor local de texto a voz de Apple. El TTS de Apple no requiere una clave de API.

Requisitos previos

  • macOS. El proyecto es solo para macOS; la app empaquetada declara macOS 12.0 o posterior.
  • Rust 1.89 o posterior y Cargo.
  • Un cliente MCP que admita HTTP transmisible.

Instalar

Instala el crate binario publicado:

cargo install isimud-text-to-speech

Verifica que Cargo haya instalado el binario isimud:

isimud --version

O compila desde este repositorio:

cargo build --release --bin isimud
./target/release/isimud --version

Configurar

isimud crea una configuración predeterminada ejecutable en el primer arranque si no existe ningún archivo de configuración. Esa configuración generada contiene una única voz default respaldada por Apple. Para comenzar con la configuración de muestra completa, crea el directorio de configuración y copia la muestra:

mkdir -p ~/.config/isimud
cp configs/config.sample.toml ~/.config/isimud/config.toml

La precedencia de la ruta de configuración es:

  1. ISIMUD_CONFIG
  2. $XDG_CONFIG_HOME/isimud/config.toml
  3. ~/.config/isimud/config.toml

Ejecutar

Inicia la app de la barra de menús y el servidor MCP:

isimud

Para operación solo de servidor:

isimud --headless

Opciones de CLI:

--headless     Run only the MCP server
-h, --help     Print help
-V, --version  Print the version

Resultado esperado:

  • En el modo de barra de menús, aparece un pequeño indicador de isimud en la barra de menús de macOS.
  • El servidor MCP escucha en http://127.0.0.1:3654/mcp.
  • Llamar a isimud.status desde tu cliente MCP devuelve state: "idle" cuando no se está hablando.

Conectar un cliente MCP

Configura tu cliente MCP con transporte HTTP transmisible:

URL: http://127.0.0.1:3654/mcp

Si estableces ISIMUD_AUTH_TOKEN o [server].auth_token, agrega este encabezado de solicitud:

Authorization: Bearer <TOKEN>

El servidor solo se vincula a direcciones IP de bucle local. Se aceptan 127.0.0.1 y ::1; los nombres de host como localhost y las direcciones que no son de bucle local como 0.0.0.0 se rechazan al inicio.

Cuando la autenticación está configurada, las solicitudes sin el token de portador exacto devuelven HTTP 401.

Hablar desde un agente

Llama a isimud.speak con texto:

{
  "text": "Build finished.",
  "voice": "default",
  "rate": 1.0
}

La llamada regresa inmediatamente de forma predeterminada:

{
  "job_id": "00000000-0000-0000-0000-000000000000",
  "queue_depth": 0
}

Establece wait en true cuando el llamador MCP deba bloquearse hasta que la emisión se complete, falle, se cancele o alcance [tts].wait_timeout_secs:

{
  "text": "Deployment complete.",
  "wait": true
}

Con wait=true, la respuesta incluye outcome:

{
  "job_id": "00000000-0000-0000-0000-000000000000",
  "queue_depth": 0,
  "outcome": "completed"
}

Configurar voces y proveedores

Las voces con nombre son el contrato de voz público para los agentes. El argumento voice de isimud.speak y [tts].default_voice debe coincidir con una clave de [voices.<name>].

[tts]
providers = ["apple", "openai", "google"]
default_voice = "default"
rate = 1.0
max_queue_depth = 64
wait_timeout_secs = 0

[voices.default]
provider = "apple"
voice = "Samantha"

[voices.narrator]
provider = "openai"
voice = "onyx"

[voices.googler]
provider = "google"
voice = "en-US-Neural2-C"
language = "en-US"

Importante: default_voice es un nombre de voz, no un nombre de proveedor. Para hacer de OpenAI el predeterminado, establece default_voice = "narrator" o crea otro bloque [voices.<name>] cuyo provider = "openai".

Los campos opcionales por voz son language, rate, pitch y volume. Una solicitud rate anula la rate de la voz, que a su vez anula [tts].rate; la volume de la voz tiene como valor predeterminado 1.0.

La disponibilidad de proveedores sigue a [tts].providers. Si el proveedor de la voz solicitada no está disponible, isimud selecciona el primer proveedor de respaldo disponible y descarta el ID de voz específico del proveedor para esa emisión de respaldo. Si no hay ningún proveedor disponible, el trabajo falla y emite un evento failed.

Configuración de proveedores

ProveedorCredencialesComportamiento
AppleNingunaUsa el comando say de macOS, reproduce en línea y enumera las voces instaladas con AVSpeechSynthesisVoice.
OpenAIOPENAI_API_KEY o [providers.openai].api_keyLlama a POST /v1/audio/speech, solicita el formato de respuesta configurado y reproduce el audio devuelto mediante rodio.
GoogleGOOGLE_API_KEY o [providers.google].api_keyLlama a Google Cloud Text-to-Speech text:synthesize, decodifica audioContent y reproduce el audio devuelto mediante rodio.

OpenAI y Google envían un valor de velocidad/ritmo solo cuando la velocidad resuelta está dentro de 0.25..=4.0. Google envía el tono solo cuando el tono resuelto está dentro de -20..=20.

ID de voz integrados de OpenAI expuestos por isimud.list_voices:

alloy ash ballad cedar coral echo fable marin nova onyx sage shimmer verse

El listado de voces de Google es intencionalmente de mejor esfuerzo y actualmente devuelve un catálogo de proveedores vacío; las voces de Google configuradas con nombre siguen funcionando.

Referencia de configuración

Consulta configs/config.sample.toml para ver la muestra completa.

ConfiguraciónPredeterminadoDescripción
[app].menubartrueEjecuta la app de bandeja de macOS. --headless desactiva la bandeja para ese proceso.
[app].autostartfalseSincroniza un LaunchAgent de macOS por usuario que inicia el ejecutable actual al iniciar sesión.
[server].host"127.0.0.1"Host de enlace de bucle local. Debe analizarse como una dirección IP.
[server].port3654Puerto HTTP de MCP.
[server].path"/mcp"Ruta HTTP transmisible de MCP.
[server].auth_tokensin establecerToken de portador opcional. ISIMUD_AUTH_TOKEN tiene prioridad.
[tts].providers["apple", "openai", "google"]Orden de respaldo de proveedores.
[tts].default_voice"default"Nombre de la entrada [voices.<name>] predeterminada.
[tts].rate1.0Multiplicador de velocidad de habla neutro.
[tts].max_queue_depth64Número de trabajos permitidos detrás de la emisión activa. 0 desactiva el límite.
[tts].wait_timeout_secs0Tiempo de espera para llamadas a wait=true. 0 espera para siempre.
[indicator.colors.*]Paleta gris/verde del sistema de AppleColores del indicador de la barra de menús. Los valores deben ser cadenas hexadecimales #RRGGBB.

El esquema TOML es estricto. Los campos desconocidos hacen fallar el análisis de configuración; la recarga en caliente mantiene la configuración anterior cuando un archivo modificado no se analiza o valida.

Variables de entorno:

VariablePropósito
ISIMUD_CONFIGAnula la resolución de la ruta de configuración.
ISIMUD_AUTH_TOKENAnula [server].auth_token.
ISIMUD_LOAD_DOTENV=0Desactiva la carga de inicio de ./.env desde el directorio de trabajo actual. También acepta false o no.
OPENAI_API_KEYHabilita el proveedor de OpenAI.
GOOGLE_API_KEYHabilita el proveedor de Google.
RUST_LOGAnula [logging].level; los objetivos útiles son runtime, server, provider, config y speech.

Las variables de entorno del shell tienen prioridad sobre .env y los secretos del archivo de configuración.

Referencia de herramientas MCP

HerramientaParámetrosResultado
isimud.speaktext obligatorio; opcionales voice, rate, waitjob_id, queue_depth; con wait=true, también outcome y error opcional.
isimud.stopningunoCancela el trabajo activo si existe y limpia los trabajos en cola. Devuelve cancelled_job y cleared.
isimud.list_voicesningunoEnumera las voces con nombre configuradas y los catálogos de voces de los proveedores.
isimud.statusningunoDevuelve state, job_id activo, voice, provider, queue_depth y degraded.

isimud.speak rechaza texto vacío y voces con nombre desconocidas como parámetros no válidos. Cuando la cola está llena, devuelve el código de error JSON-RPC -32010 con esta carga útil de datos:

{
  "queue_depth": 64,
  "capacity": 64
}

Los pares MCP conectados reciben notificaciones personalizadas isimud/speech_event para estos eventos del ciclo de vida:

enqueued started finished failed stopped degraded

Las solicitudes MCP personalizadas denominadas isimud/quit o isimud/exit activan un apagado ordenado.

Comportamiento en tiempo de ejecución

isimud ejecuta un único trabajador de habla. Los trabajos nunca se superponen; cada emisión aceptada espera a que la emisión actual termine o se cancele.

El trabajo activo no cuenta para [tts].max_queue_depth. Esa configuración solo limita los trabajos que esperan detrás de la emisión activa.

Guardar el archivo de configuración recarga en caliente el motor de habla y la paleta de la bandeja. Los cambios válidos actualizan voces, credenciales de proveedores, velocidades de habla, configuración de cola y colores de la bandeja sin reiniciar. Las ediciones no válidas se registran y la configuración anterior permanece activa.

La configuración de enlace del servidor ([server].host, [server].port, [server].path y autenticación) y la sincronización de inicio automático del LaunchAgent se aplican al inicio. Reinicia isimud después de cambiar esas configuraciones.

El icono de la bandeja de macOS es gris cuando está inactivo y pulsa en verde mientras habla. Si el trabajador de habla sale inesperadamente o un trabajo entra en pánico, isimud.status informa degraded: true y se transmite un evento degraded.

Funciones de la app de macOS

Esquema de URL

La app empaquetada registra el esquema de URL isimud://. Úsalo para poner en cola el habla desde enlaces de macOS o automatización:

isimud://speak/Hello%20world
isimud://speak?text=Hello%20world&voice=narrator&rate=1.25

El texto de la ruta tiene prioridad sobre el parámetro de consulta text cuando ambos están presentes. El esquema de URL está disponible al ejecutar el .app empaquetado que incluye la entrada CFBundleURLTypes.

Clic en la bandeja

En el modo de barra de menús, un clic izquierdo en el icono de la bandeja intenta ejecutar el comando opcional fortune y hablar su salida. Si fortune no está instalado o no devuelve texto, el clic se ignora y se registra una advertencia.

Inicio automático

Establece [app].autostart = true para sincronizar un LaunchAgent por usuario en ~/Library/LaunchAgents/com.bnomei.isimud.plist. El LaunchAgent usa la ruta del ejecutable actual y establece ISIMUD_CONFIG en la ruta de configuración resuelta.

Al ejecutar el .app empaquetado, prefiere los elementos de inicio de sesión de macOS si deseas un comportamiento de inicio tipo app.

Empaquetado

Compila un binario de lanzamiento para un objetivo:

TARGET=aarch64-apple-darwin scripts/build-release.sh

Compila un paquete de app de macOS y un archivo zip a partir de un binario de lanzamiento existente:

TARGET=aarch64-apple-darwin scripts/package-macos-app.sh

Si compilaste el objetivo host predeterminado con cargo build --release --bin isimud, ejecuta scripts/package-macos-app.sh sin TARGET.

Variables de empaquetado útiles:

VariablePredeterminadoDescripción
BIN_NAMEisimudNombre del binario copiado en el paquete de la app.
PRODUCT_NAMEIsimudNombre del producto del paquete de la app.
BUNDLE_IDENTIFIERcom.bnomei.isimudIdentificador de paquete de macOS.
TARGETsin establecerSelecciona target/<TARGET>/release/isimud como ruta del binario.
BIN_PATHsin establecerRuta explícita del binario. Anula TARGET.
ICON_PATHpackaging/macos/Isimud.icnsIcono opcional copiado en el paquete de la app cuando está presente.
CODESIGN_APP1Firma ad-hoc con codesign --sign -. Establécelo en 0 si codesign no está disponible.
ZIP_APP1Establécelo en 0 para omitir la creación del zip.

Crea un archivo de lanzamiento tar a partir de un objetivo compilado:

VERSION=$(scripts/resolve-version.sh) TARGET=aarch64-apple-darwin scripts/package-release.sh

Desarrollo

Ejecuta las comprobaciones principales:

cargo test
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings

Este repositorio también incluye hooks de prek:

prek install
prek run --all-files

Limitaciones actuales

  • macOS es la única plataforma compatible.
  • El servidor MCP solo admite HTTP transmisible; no hay transporte stdio.
  • El servidor se vincula únicamente a direcciones de loopback.
  • Apple say respeta rate pero no aplica volume ni pitch.
  • Los tiempos de espera de solicitudes de OpenAI y Google se dejan al cliente HTTP y al comportamiento del proveedor/red. [tts].wait_timeout_secs solo limita cuánto tiempo espera una llamada MCP wait=true por el resultado del trabajo; no cancela la síntesis.
  • isimud valida que text no esté vacío, pero no impone un límite fijo de caracteres, bytes, tokens o tamaño de respuesta del proveedor.
  • El audio del proveedor de nube se decodifica y reproduce en memoria, por lo que expresiones muy largas pueden aumentar el uso de memoria y la latencia de reproducción.

Mapa de fuentes

Licencia

MIT. Ver LICENSE.