Isimud
Faça seu agente falar com você (apenas OSX)
Documentação
isimud
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 é:
ISIMUD_CONFIG$XDG_CONFIG_HOME/isimud/config.toml~/.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.statusdo seu cliente MCP retornastate: "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
| Provedor | Credenciais | Comportamento |
|---|---|---|
| Apple | Nenhuma | Usa o comando say do macOS, reproduz inline e enumera as vozes instaladas com AVSpeechSynthesisVoice. |
| OpenAI | OPENAI_API_KEY ou [providers.openai].api_key | Chama POST /v1/audio/speech, solicita o formato de resposta configurado e reproduz o áudio retornado por meio de rodio. |
GOOGLE_API_KEY ou [providers.google].api_key | Chama 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ção | Padrão | Descrição |
|---|---|---|
[app].menubar | true | Executa o aplicativo de bandeja do macOS. --headless desativa a bandeja para esse processo. |
[app].autostart | false | Sincroniza 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].port | 3654 | Porta HTTP do MCP. |
[server].path | "/mcp" | Caminho HTTP transmissível do MCP. |
[server].auth_token | não definido | Token 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].rate | 1.0 | Multiplicador de taxa de fala neutra. |
[tts].max_queue_depth | 64 | Número de trabalhos permitidos atrás do enunciado ativo. 0 desativa o limite. |
[tts].wait_timeout_secs | 0 | Tempo limite para chamadas wait=true. 0 espera para sempre. |
[indicator.colors.*] | Paleta cinza/verde do sistema Apple | Cores 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ável | Finalidade |
|---|---|
ISIMUD_CONFIG | Substitui a resolução do caminho de configuração. |
ISIMUD_AUTH_TOKEN | Substitui [server].auth_token. |
ISIMUD_LOAD_DOTENV=0 | Desativa o carregamento inicial de ./.env do diretório de trabalho atual. Também aceita false ou no. |
OPENAI_API_KEY | Habilita o provedor OpenAI. |
GOOGLE_API_KEY | Habilita o provedor Google. |
RUST_LOG | Substitui [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
| Ferramenta | Parâmetros | Resultado |
|---|---|---|
isimud.speak | text obrigatório; opcionais voice, rate, wait | job_id, queue_depth; com wait=true, também outcome e opcional error. |
isimud.stop | nenhum | Cancela o trabalho ativo, se presente, e limpa os trabalhos na fila. Retorna cancelled_job e cleared. |
isimud.list_voices | nenhum | Lista as vozes nomeadas configuradas e os catálogos de vozes do provedor. |
isimud.status | nenhum | Retorna 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ável | Padrão | Descrição |
|---|---|---|
BIN_NAME | isimud | Nome do binário copiado para o pacote do aplicativo. |
PRODUCT_NAME | Isimud | Nome do produto do pacote do aplicativo. |
BUNDLE_IDENTIFIER | com.bnomei.isimud | Identificador do bundle macOS. |
TARGET | não definido | Seleciona target/<TARGET>/release/isimud como o caminho do binário. |
BIN_PATH | não definido | Caminho explícito do binário. Substitui TARGET. |
ICON_PATH | packaging/macos/Isimud.icns | Ícone opcional copiado para o pacote do aplicativo quando presente. |
CODESIGN_APP | 1 | Assina ad-hoc com codesign --sign -. Defina como 0 se codesign não estiver disponível. |
ZIP_APP | 1 | Defina 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
sayhonrarate, mas não aplicavolumenempitch. - 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_secsapenas limita quanto tempo uma chamada MCPwait=trueaguarda o resultado do trabalho; ele não cancela a síntese. - O isimud valida que
textnã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
- Carregamento de configuração e padrões: src/config.rs
- Ferramentas MCP e distribuição de notificações: src/mcp.rs
- Servidor HTTP e aplicação de loopback/autenticação: src/server.rs
- Resolução de vozes nomeadas: src/voices.rs
- Fila de fala e worker: src/worker.rs
- Registro de provedores e fallback: src/providers/mod.rs
- Comportamento da bandeja do macOS: src/runtime_tray.rs
- Análise de esquema de URL: src/url_scheme.rs
- Modelo de pacote de aplicativo macOS: packaging/macos/Info.plist.template
Licença
MIT. Consulte LICENSE.