Isimud

Faça seu agente falar com você (apenas OSX)

Documentação

isimud

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

isimud é um aplicativo de barra de menus do macOS e um servidor MCP HTTP transmissível que permite que agentes de IA falem. Um agente envia texto para uma ferramenta MCP; o isimud resolve uma voz nomeada, sintetiza a fala por meio da Apple, OpenAI ou Google e a reproduz por meio de uma única fila de fala serializada.

isimud é a contraparte de texto para fala do muninn, que transforma fala em texto para agentes.

Use o isimud quando quiser:

  • Um aplicativo local de bandeja do macOS que pulsa enquanto um agente está falando.
  • Um servidor MCP sem interface para uso em scripts ou em segundo plano.
  • Texto para fala com foco local e provedores de nuvem opcionais com sua própria chave.
  • Vozes nomeadas que ocultam IDs de voz específicos do provedor dos agentes.
  • Fila, cancelamento, status e notificações de ciclo de vida da fala via MCP.

Início rápido

Complete este caminho para executar o isimud com o provedor local de texto para fala da Apple. O TTS da Apple não requer chave de API.

Pré-requisitos

  • macOS. O projeto é exclusivo para macOS; o aplicativo empacotado declara macOS 12.0 ou mais recente.
  • Rust 1.89 ou mais recente e Cargo.
  • Um cliente MCP que suporte HTTP transmissível.

Instalação

Instale o crate binário publicado:

cargo install isimud-text-to-speech

Verifique se o Cargo instalou o binário isimud:

isimud --version

Ou compile a partir deste repositório:

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

Configuração

O isimud cria uma configuração padrão inicializável na primeira execução se nenhum arquivo de configuração existir. Essa configuração gerada contém uma única voz default com suporte da Apple. Para começar com a configuração de exemplo completa, crie o diretório de configuração e copie o exemplo:

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

A precedência do caminho de configuração é:

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

Execução

Inicie o aplicativo de barra de menus e o servidor MCP:

isimud

Para operação somente com servidor:

isimud --headless

Opções de CLI:

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

Resultado esperado:

  • No modo de barra de menus, um pequeno indicador do isimud aparece na barra de menus do macOS.
  • O servidor MCP escuta em http://127.0.0.1:3654/mcp.
  • Chamar isimud.status do seu cliente MCP retorna state: "idle" quando nada está falando.

Conectar um cliente MCP

Configure seu cliente MCP com transporte HTTP transmissível:

URL: http://127.0.0.1:3654/mcp

Se você definir ISIMUD_AUTH_TOKEN ou [server].auth_token, adicione este cabeçalho de solicitação:

Authorization: Bearer <TOKEN>

O servidor só vincula a endereços IP de loopback. 127.0.0.1 e ::1 são aceitos; nomes de host como localhost e endereços não loopback como 0.0.0.0 são rejeitados na inicialização.

Quando a autenticação está configurada, solicitações sem o token de portador exato retornam HTTP 401.

Falar a partir de um agente

Chame isimud.speak com texto:

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

A chamada retorna imediatamente por padrão:

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

Defina wait como true quando o chamador MCP deve bloquear até que o enunciado seja concluído, falhe, seja cancelado ou atinja [tts].wait_timeout_secs:

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

Com wait=true, a resposta inclui outcome:

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

Configurar vozes e provedores

Vozes nomeadas são o contrato público de voz para agentes. O argumento voice para isimud.speak e [tts].default_voice deve corresponder a uma chave [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 é um nome de voz, não um nome de provedor. Para tornar a OpenAI o padrão, defina default_voice = "narrator" ou crie outro bloco [voices.<name>] cujo provider = "openai".

Campos opcionais por voz são language, rate, pitch e volume. Uma solicitação rate substitui a voz rate, que substitui [tts].rate; a voz volume tem como padrão 1.0.

A disponibilidade do provedor segue [tts].providers. Se o provedor da voz solicitada não estiver disponível, o isimud seleciona o primeiro provedor de fallback disponível e descarta o ID de voz específico do provedor para esse enunciado de fallback. Se nenhum provedor estiver disponível, o trabalho falha e emite um evento failed.

Configuração do provedor

ProvedorCredenciaisComportamento
AppleNenhumaUsa o comando say do macOS, reproduz inline e enumera as vozes instaladas com AVSpeechSynthesisVoice.
OpenAIOPENAI_API_KEY ou [providers.openai].api_keyChama POST /v1/audio/speech, solicita o formato de resposta configurado e reproduz o áudio retornado por meio de rodio.
GoogleGOOGLE_API_KEY ou [providers.google].api_keyChama o Google Cloud Text-to-Speech text:synthesize, decodifica audioContent e reproduz o áudio retornado por meio de rodio.

OpenAI e Google enviam um valor de taxa/velocidade apenas quando a taxa resolvida está dentro de 0.25..=4.0. O Google envia pitch apenas quando o pitch resolvido está dentro de -20..=20.

IDs de voz integrados da OpenAI expostos por isimud.list_voices:

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

A listagem de vozes do Google é intencionalmente de melhor esforço e atualmente retorna um catálogo de provedor vazio; vozes nomeadas do Google configuradas ainda funcionam.

Referência de configuração

Consulte configs/config.sample.toml para o exemplo completo.

ConfiguraçãoPadrãoDescrição
[app].menubartrueExecuta o aplicativo de bandeja do macOS. --headless desativa a bandeja para esse processo.
[app].autostartfalseSincroniza um LaunchAgent do macOS por usuário que inicia o executável atual no login.
[server].host"127.0.0.1"Host de bind de loopback. Deve ser analisado como um endereço IP.
[server].port3654Porta HTTP do MCP.
[server].path"/mcp"Caminho HTTP transmissível do MCP.
[server].auth_tokennão definidoToken de portador opcional. ISIMUD_AUTH_TOKEN tem precedência.
[tts].providers["apple", "openai", "google"]Ordem de fallback do provedor.
[tts].default_voice"default"Nome da entrada [voices.<name>] padrão.
[tts].rate1.0Multiplicador de taxa de fala neutra.
[tts].max_queue_depth64Número de trabalhos permitidos atrás do enunciado ativo. 0 desativa o limite.
[tts].wait_timeout_secs0Tempo limite para chamadas wait=true. 0 espera para sempre.
[indicator.colors.*]Paleta cinza/verde do sistema AppleCores do indicador da barra de menus. Os valores devem ser strings hexadecimais #RRGGBB.

O esquema TOML é estrito. Campos desconhecidos falham na análise da configuração; a recarga a quente mantém a configuração anterior quando um arquivo alterado falha ao analisar ou validar.

Variáveis de ambiente:

VariávelFinalidade
ISIMUD_CONFIGSubstitui a resolução do caminho de configuração.
ISIMUD_AUTH_TOKENSubstitui [server].auth_token.
ISIMUD_LOAD_DOTENV=0Desativa o carregamento inicial de ./.env do diretório de trabalho atual. Também aceita false ou no.
OPENAI_API_KEYHabilita o provedor OpenAI.
GOOGLE_API_KEYHabilita o provedor Google.
RUST_LOGSubstitui [logging].level; alvos úteis são runtime, server, provider, config e speech.

As variáveis de ambiente do shell têm precedência sobre .env e segredos do arquivo de configuração.

Referência de ferramentas MCP

FerramentaParâmetrosResultado
isimud.speaktext obrigatório; opcionais voice, rate, waitjob_id, queue_depth; com wait=true, também outcome e opcional error.
isimud.stopnenhumCancela o trabalho ativo, se presente, e limpa os trabalhos na fila. Retorna cancelled_job e cleared.
isimud.list_voicesnenhumLista as vozes nomeadas configuradas e os catálogos de vozes do provedor.
isimud.statusnenhumRetorna state, ativo job_id, voice, provider, queue_depth e degraded.

isimud.speak rejeita texto vazio e vozes nomeadas desconhecidas como parâmetros inválidos. Quando a fila está cheia, retorna o código de erro JSON-RPC -32010 com este payload de dados:

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

Os pares MCP conectados recebem notificações personalizadas isimud/speech_event para estes eventos de ciclo de vida:

enqueued started finished failed stopped degraded

Solicitações MCP personalizadas chamadas isimud/quit ou isimud/exit disparam desligamento gracioso.

Comportamento em tempo de execução

O isimud executa um único worker de fala. Os trabalhos nunca se sobrepõem; cada enunciado aceito aguarda o enunciado atual terminar ou ser cancelado.

O trabalho ativo não conta para [tts].max_queue_depth. Essa configuração apenas limita os trabalhos que aguardam atrás do enunciado ativo.

Salvar o arquivo de configuração recarrega a quente o mecanismo de fala e a paleta da bandeja. Alterações válidas atualizam vozes, credenciais do provedor, taxas de fala, configurações de fila e cores da bandeja sem reiniciar. Edições inválidas são registradas e a configuração anterior permanece ativa.

As configurações de bind do servidor ([server].host, [server].port, [server].path e autenticação) e a sincronização de inicialização automática do LaunchAgent são aplicadas na inicialização. Reinicie o isimud após alterar essas configurações.

O ícone da bandeja do macOS fica cinza quando ocioso e pulsa verde enquanto fala. Se o worker de fala sair inesperadamente ou um trabalho entrar em pânico, isimud.status relata degraded: true e um evento degraded é transmitido.

Recursos do aplicativo macOS

Esquema de URL

O aplicativo empacotado registra o esquema de URL isimud://. Use-o para enfileirar fala a partir de links ou automação do macOS:

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

O texto do caminho tem precedência sobre o parâmetro de consulta text quando ambos estão presentes. O esquema de URL está disponível ao executar o .app empacotado que inclui a entrada CFBundleURLTypes.

Clique na bandeja

No modo de barra de menus, um clique esquerdo no ícone da bandeja tenta executar o comando opcional fortune e falar sua saída. Se fortune não estiver instalado ou não retornar texto, o clique é ignorado e um aviso é registrado.

Inicialização automática

Defina [app].autostart = true para sincronizar um LaunchAgent por usuário em ~/Library/LaunchAgents/com.bnomei.isimud.plist. O LaunchAgent usa o caminho do executável atual e define ISIMUD_CONFIG para o caminho de configuração resolvido.

Ao executar o .app empacotado, prefira os Itens de Login do macOS se quiser um comportamento de inicialização no estilo de aplicativo.

Empacotamento

Compile um binário de release para um alvo:

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

Compile um pacote de aplicativo macOS e um arquivo zip a partir de um binário de release existente:

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

Se você compilou o alvo host padrão com cargo build --release --bin isimud, execute scripts/package-macos-app.sh sem TARGET.

Variáveis de empacotamento úteis:

VariávelPadrãoDescrição
BIN_NAMEisimudNome do binário copiado para o pacote do aplicativo.
PRODUCT_NAMEIsimudNome do produto do pacote do aplicativo.
BUNDLE_IDENTIFIERcom.bnomei.isimudIdentificador do bundle macOS.
TARGETnão definidoSeleciona target/<TARGET>/release/isimud como o caminho do binário.
BIN_PATHnão definidoCaminho explícito do binário. Substitui TARGET.
ICON_PATHpackaging/macos/Isimud.icnsÍcone opcional copiado para o pacote do aplicativo quando presente.
CODESIGN_APP1Assina ad-hoc com codesign --sign -. Defina como 0 se codesign não estiver disponível.
ZIP_APP1Defina como 0 para pular a criação do zip.

Crie um arquivo de release tarball a partir de um alvo compilado:

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

Desenvolvimento

Execute as verificações principais:

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

Este repositório também inclui ganchos prek:

prek install
prek run --all-files

Limitações atuais

  • macOS é a única plataforma suportada.
  • O servidor MCP suporta apenas HTTP com streaming; não há transporte stdio.
  • O servidor vincula-se apenas a endereços de loopback.
  • O Apple say honra rate, mas não aplica volume nem pitch.
  • Os tempos limite de solicitação da OpenAI e do Google ficam a cargo do cliente HTTP e do comportamento do provedor/rede. O [tts].wait_timeout_secs apenas limita quanto tempo uma chamada MCP wait=true aguarda o resultado do trabalho; ele não cancela a síntese.
  • O isimud valida que text não está vazio, mas não impõe um limite fixo de caracteres, bytes, tokens ou tamanho de resposta do provedor.
  • O áudio do provedor de nuvem é decodificado e reproduzido em memória, portanto, enunciados muito longos podem aumentar o uso de memória e a latência de reprodução.

Mapa de fontes

Licença

MIT. Consulte LICENSE.