NotificaΓ§Γ΅es nativas cross-platform para o Claude Code, com traduΓ§Γ£o pt-BR / en-US.
Native cross-platform notifications for Claude Code, with pt-BR / en-US translation.
O Ringly liga os hooks do Claude Code (Notification, Stop, StopFailure, SubagentStop)
a notificaΓ§Γ΅es nativas do sistema operacional, com mensagens traduzidas e contextualizadas
pelo nome do projeto. VocΓͺ nunca mais precisa ficar olhando o terminal pra saber o que o
Claude estΓ‘ esperando de vocΓͺ.
O projeto Γ© distribuΓdo em duas camadas complementares e obrigatΓ³rias, nesta ordem:
- Pacote npm
ringly(passo 1) β registra o AUMID do Windows (sem ele, o Windows 10/11 silencia o toast nativo), instala o atalho no Menu Iniciar, escreve a configuraΓ§Γ£o inicial e fornece os utilitΓ‘riosringly doctor/ringly config/ringly uninstall. - Plugin do Claude Code (passo 2) β registra os hooks (
Notification,Stop,StopFailure,SubagentStop) e roda o dispatcher que delega ao mΓ³dulo Node doringlye, por fim, monta e dispara o toast usando o AUMID jΓ‘ registrado no passo 1.
β οΈ Os dois passos sΓ£o obrigatΓ³rios. O plugin sozinho atΓ© roda o dispatcher, mas no Windows 10/11 oToastNotificationManagerexige um AUMID registrado para exibir notificaΓ§Γ΅es na Central de AΓ§Γ΅es β esse registro Γ© feito apenas peloringly init. Sem ele, vocΓͺ ouve no mΓ‘ximo um beep de fallback (ou nada).
O Ringly estΓ‘ em desenvolvimento ativo. Windows 10 e 11 sΓ£o os sistemas suportados na v1.0. macOS e Linux tΓͺm os back-ends estruturados e estΓ£o planejados para a prΓ³xima versΓ£o.
| Recurso | Windows 10/11 | macOS | Linux |
|---|---|---|---|
| Toast nativo | β | β³ | β³ |
| Som de fallback | β | β³ | β³ |
| Registro AUMID | β | β | β |
| NotificaΓ§Γ΅es em pt-BR/en-US | β | β | β |
| TUI e CLI em pt-BR/en-US | β | β | β |
A instalaΓ§Γ£o Γ© feita em dois passos. Pule um e o toast nativo nΓ£o vai aparecer no Windows 10/11 β nΓ£o Γ© uma escolha, Γ© uma exigΓͺncia do prΓ³prio sistema operacional (veja a nota acima sobre o AUMID).
npm install -g ringly
ringly initO instalador interativo:
- registra o AUMID
Claude.Code.CLIno Windows (obrigatΓ³rio para que oToastNotificationManagerautorize o toast), - cria o atalho no Menu Iniciar amarrado a esse AUMID,
- salva a configuraΓ§Γ£o no
~/.claude/settings.json(com backup automΓ‘tico), - imprime o comando exato do passo 2 pra vocΓͺ colar no Claude Code.
Dentro do Claude Code:
/plugin marketplace add nickdevcode/Ringly
/plugin install ringly@ringly
O plugin registra os hooks (Notification, Stop, StopFailure, SubagentStop)
e o dispatcher embutido passa a usar o AUMID jΓ‘ registrado no passo 1. A partir
daΓ, configure idioma, eventos, som e debug pelo ringly config (TUI) ou
editando ~/.claude/settings.json direto β a partir da v0.5.0 o Ringly nΓ£o
expΓ΅e mais uma tela no gerenciador de plugins do Claude Code (veja a seΓ§Γ£o
ConfiguraΓ§Γ£o para o porquΓͺ).
A partir da v0.4.0, o prΓ³prio Ringly te avisa quando tem uma versΓ£o nova:
-
Aviso automΓ‘tico. Uma vez por dia, no inΓcio da sessΓ£o do Claude Code, o plugin checa o npm em background. Se tiver versΓ£o nova, dispara uma toast nativa do tipo "Ringly 0.5.0 disponΓvel β rode
/ringly-updateno Claude Code". Γ a mesma toast que vocΓͺ jΓ‘ conhece, sΓ³ vinda do prΓ³prio plugin. -
AtualizaΓ§Γ£o guiada via slash command. Dentro do Claude Code, rode:
/ringly-updateO comando consulta o npm, mostra a diferenΓ§a entre a versΓ£o instalada e a mais recente, pede confirmaΓ§Γ£o e roda
npm install -g ringly@latestpor vocΓͺ. No final, ele lembra de rodar/reload-pluginspara a sessΓ£o ativa carregar a nova versΓ£o (ou fechar e reabrir o Claude Code se houver lock de arquivos no Windows).
Se preferir fazer na mΓ£o (ou estiver fora do Claude Code):
npm install -g ringly@latestVerifique a versΓ£o instalada com ringly --version ou ringly update --check
(esse ΓΊltimo imprime um JSON com current, latest, hasUpdate, reachable β
ΓΊtil em scripts e CI). O plugin do Claude Code atualiza automaticamente quando
uma nova versΓ£o Γ© publicada no marketplace; force com /plugin marketplace update
dentro do Claude Code se quiser puxar manualmente.
A checagem Γ© throttled a uma request por dia, nΓ£o envia nada alΓ©m da consulta
pΓΊblica ao npm e respeita o opt-out. Pra desligar, marque check_updates: false
rodando ringly config ou editando ~/.claude/settings.json direto.
A partir da v0.5.0, o Ringly Γ© configurado exclusivamente pela CLI. O
plugin.jsonnΓ£o declara mais umuserConfig, entΓ£o a tela/pluginβ Installed β Ringly β Configure do Claude Code nΓ£o aparece de propΓ³sito. Mais sobre o porquΓͺ logo abaixo.
AtΓ© a v0.4.x o Ringly aparecia no /plugin manager nativo. Na prΓ‘tica a UX era
ruim e cheia de armadilhas que vinham do prΓ³prio gerenciador, nΓ£o do nosso plugin:
- O campo
languageera um input de texto livre. O schema oficial douserConfig(documentado pela Anthropic emcode.claude.com) sΓ³ permitestring/number/boolean/directory/fileβ nΓ£o tem suporte a enum. Resultado: o usuΓ‘rio precisava digitarpt-BRouen-USletra por letra (com hΓfen), e um typo viravaautosilenciosamente. Enterem booleano nΓ£o toggle. No plugin manager,Enterapenas confirma a navegaΓ§Γ£o entre campos. Pra alternar um boolean vocΓͺ precisava lembrar de apertarSpace. VΓ‘rias pessoas reportaram "marquei a opΓ§Γ£o mas continuou ligada".- Sem validaΓ§Γ£o visual, sem confirmaΓ§Γ£o atΓ΄mica. O plugin manager grava direto em
~/.claude/settings.jsonsem backup explΓcito e sem aviso de/reload-plugins.
Nada disso Γ© culpa do Claude Code β o userConfig Γ© um schema genΓ©rico e
funciona bem pra plugins simples (uma URL, um token). Pro caso do Ringly (idioma
com enum, 7 toggles, contexto de "isso vai disparar notificaΓ§Γ΅es no seu SO"), o
custo da UX ruim era maior do que o ganho de ter uma tela nativa.
A soluΓ§Γ£o tΓ©cnica seria pedir pra Anthropic adicionar enum e Enter-toggle no
schema. Enquanto isso nΓ£o acontece, optamos por remover o userConfig
completamente em vez de fingir que a UX Γ© boa.
| Forma | Quando usar |
|---|---|
ringly config β TUI bonita no terminal (β¨ recomendado) |
Melhor experiΓͺncia: setas pra navegar, espaΓ§o pra toggle, seletor visual de idioma. Escreve no settings.json por vocΓͺ (atomic + backup com timestamp) e lembra de rodar /reload-plugins ao final. |
Editar settings.json manualmente |
Para automaΓ§Γ£o/CI. As chaves ficam em pluginConfigs.ringly.options (veja OpΓ§Γ΅es disponΓveis). Sempre rode /reload-plugins depois. |
ringly init |
Roda o instalador interativo de novo (com banner, registro de AUMID, setup completo). Use quando estiver reinstalando ou se o settings.json foi apagado. |
Se vocΓͺ procurar pelo Ringly em
/plugin β Installed, o plugin aparece lΓ‘ (ele estΓ‘ instalado β os hooks estΓ£o registrados), mas o item Configure simplesmente nΓ£o existe pro Ringly. Isso Γ© proposital, nΓ£o bug.
O dispatcher dos hooks lΓͺ, nesta ordem de prioridade:
~/.claude/settings.jsonβpluginConfigs.ringly.optionsβ fonte ΓΊnica em estado estΓ‘vel. O Ringly lΓͺ esse arquivo diretamente no inΓcio de cada hook, entΓ£o qualquer mudanΓ§a feita porringly configΓ© aplicada imediatamente, sem precisar de restart.- VariΓ‘veis de ambiente
RINGLY_DEBUG=1eCLAUDE_PLUGIN_OPTION_*β overrides volΓ‘teis. AsCLAUDE_PLUGIN_OPTION_*continuam sendo lidas como override opcional (ΓΊtil pra forΓ§ardebug=truepor uma ΓΊnica sessΓ£o sem persistir nada), mas o Claude Code nΓ£o exporta mais nada automaticamente jΓ‘ que ouserConfigfoi removido. VocΓͺ precisa setar essas variΓ‘veis manualmente no seu shell se quiser usar. - Defaults internos β ΓΊltima camada.
As chaves abaixo ficam em pluginConfigs.ringly.options dentro de ~/.claude/settings.json. O ringly config cria/edita todas elas pra vocΓͺ.
| Chave | Tipo | PadrΓ£o | DescriΓ§Γ£o |
|---|---|---|---|
language |
auto / pt-BR / en-US |
auto |
auto detecta pelo locale do sistema. |
events_notification |
boolean | true | Notifica quando o Claude pede permissΓ£o ou input. |
events_stop |
boolean | true | Notifica quando o Claude termina uma resposta. |
events_stopFailure |
boolean | true | Notifica quando um erro de API encerra a sessΓ£o. |
events_subagentStop |
boolean | false | Notifica quando um subagent termina. |
sound |
boolean | true | Toca som junto da notificaΓ§Γ£o. |
debug |
boolean | false | Escreve logs detalhados. |
check_updates |
boolean | true | Checa o npm 1x/dia no SessionStart e avisa via toast quando tem versΓ£o nova. |
ringly help # lista os comandos no idioma configurado
ringly init # instalador interativo (TUI)
ringly init --non-interactive # aplica defaults, sem TUI
ringly config # reconfigura interativamente
ringly doctor # diagnΓ³stico do ambiente local
ringly test --event Stop --lang pt-BR
ringly update # checa o npm e roda a atualizaΓ§Γ£o guiada
ringly update --check # imprime JSON {current, latest, hasUpdate, reachable, language, notes}
ringly update --yes # pula a confirmaΓ§Γ£o e instala direto
ringly uninstall # remove AUMID, atalho e configuraΓ§Γ΅es do RinglyDentro do Claude Code, dois slash commands cobrem o dia a dia:
/ringly-updateβ espelharingly update, com confirmaΓ§Γ£o visual viaAskUserQuestion, resumo amigΓ‘vel do que mudou na nova versΓ£o (lido doCHANGELOG.mdempacotado) e instruΓ§Γ£o automΓ‘tica pra rodar/reload-pluginsno final. Tudo aparece no idioma configurado./ringly-helpβ rodaringly helpe mostra a lista de comandos direto no chat (com aviso de que esses comandos rodam no seu terminal externo, nΓ£o dentro do Claude Code).
- O Claude Code emite um evento de hook (
SessionStart,Notification,Stop,StopFailure,SubagentStop). - O
hooks.jsondo plugin executanode ${CLAUDE_PLUGIN_ROOT}/hooks/dispatch.mjs <Event>. - O
dispatch.mjslΓͺ o~/.claude/settings.jsone checa as opΓ§Γ΅es do Ringly. Se o evento estiver desabilitado pelo usuΓ‘rio (events_*oucheck_updates), o dispatcher encerra silenciosamente β sem disparar nada. OSessionStartΓ© tratado como um caminho separado: em vez de virar toast direto, ele dispara uma checagem de versΓ£o (throttled a 24h) que sΓ³ vira toast se o npm tiver versΓ£o nova. - Caso o evento esteja habilitado, o dispatcher lΓͺ o payload JSON via stdin e tenta, nessa ordem:
- o mΓ³dulo Node
ringly/hookβ caminho normal quando a CLI foi instalada (passo 1 da instalaΓ§Γ£o). Traz a traduΓ§Γ£o mais rica e contexto de projeto. - o binΓ‘rio
ringlyno PATH β usado quando o mΓ³dulo nΓ£o Γ© resolvido pelorequiremas a CLI existe globalmente. - um fallback embutido em PowerShell + WinRT β ΓΊltimo recurso, sΓ³ dispara
se os dois anteriores falharem. Como o AUMID
Claude.Code.CLIprecisa estar registrado peloringly init, esse fallback nΓ£o substitui o passo 1: sem CLI, ele toca no mΓ‘ximo um beep e sai.
- o mΓ³dulo Node
- No Windows, o toast Γ© gerado como XML e exibido via o AUMID registrado
Claude.Code.CLI. Um beep Γ© tocado como fallback se o Modo Foco ou NΓ£o Perturbe estiverem bloqueando as notificaΓ§Γ΅es.
- NΓ£o aparece toast: confira Modo Foco ou NΓ£o Perturbe no Windows. Rode
ringly doctorpara inspecionar o registro AUMID e as permissΓ΅es. - AUMID ausente: rode
ringly init --forcepara recriar o atalho do Menu Iniciar e re-registrar o ID da aplicaΓ§Γ£o. - Hook parece silencioso: ative
debug: truena config do plugin e verifique o log mostrado no fim doringly doctor.
Issues e pull requests sΓ£o bem-vindos. Leia o CONTRIBUTING.md
antes de abrir uma PR β ele tem o setup local, padrΓ΅es de commit e como rodar
os checks.
HistΓ³rico de versΓ΅es: CHANGELOG.md.
RepositΓ³rio: github.com/nickdevcode/Ringly.
Ringly wires up the Claude Code hook system (Notification, Stop, StopFailure,
SubagentStop) to native operating-system notifications, with translated, project-aware
messages so you always know what Claude needs from you without staring at your terminal.
It is distributed as two complementary layers, both required, in this order:
ringlynpm package (step 1) β registers the Windows AUMID (without it Windows 10/11 silently drops the native toast), installs the Start Menu shortcut, writes the initial configuration, and ships theringly doctor/ringly config/ringly uninstallutilities.- Claude Code plugin (step 2) β registers the hooks (
Notification,Stop,StopFailure,SubagentStop) and runs the dispatcher that delegates to theringlyNode module and ultimately builds and shows the toast using the AUMID already registered in step 1.
β οΈ Both steps are required. The plugin alone runs the dispatcher, but on Windows 10/11ToastNotificationManageronly displays notifications from apps with a registered AUMID β and that registration is performed exclusively byringly init. Skip it and you'll get a fallback beep at best, nothing at worst.
Ringly is in active development. Windows 10 and 11 are the supported targets for v1.0. macOS and Linux toast back-ends are scaffolded and planned for the next release.
| Surface | Windows 10/11 | macOS | Linux |
|---|---|---|---|
| Native toast | β | β³ | β³ |
| Sound fallback | β | β³ | β³ |
| AUMID register | β | β | β |
| Notifications in pt-BR/en-US | β | β | β |
| TUI & CLI in pt-BR/en-US | β | β | β |
Installation is a two-step process. Skip either one and native toasts won't show up on Windows 10/11 β this isn't a choice, it's an OS-level requirement (see the note above about the AUMID).
npm install -g ringly
ringly initThe interactive installer:
- registers the
Claude.Code.CLIAUMID on Windows (required forToastNotificationManagerto authorize the toast), - creates a Start Menu shortcut bound to that AUMID,
- writes the configuration to
~/.claude/settings.json(with an automatic backup), - prints the exact step 2 command to paste into Claude Code.
Inside Claude Code:
/plugin marketplace add nickdevcode/Ringly
/plugin install ringly@ringly
The plugin registers the hooks (Notification, Stop, StopFailure,
SubagentStop) and the embedded dispatcher uses the AUMID registered in step 1.
From here, tweak language, events, sound, and debug via ringly config (TUI)
or by editing ~/.claude/settings.json directly β starting with v0.5.0 the
plugin no longer exposes a Claude Code plugin-manager screen (see the
Configuration section for why).
Starting in v0.4.0, Ringly tells you when there's a new version available:
-
Automatic notice. Once a day, at the start of a Claude Code session, the plugin checks npm in the background. If a newer version is out, it fires the same native toast you already know β "Ringly 0.5.0 available β run
/ringly-updateinside Claude Code". -
Guided update via slash command. Inside Claude Code, run:
/ringly-updateThe command queries npm, shows the diff between the installed and the latest version, asks for confirmation, and runs
npm install -g ringly@latestfor you. At the end it reminds you to run/reload-pluginsso the active session picks up the new version (or close and reopen Claude Code if Windows holds the files locked).
If you'd rather do it by hand (or you're outside Claude Code):
npm install -g ringly@latestCheck the installed version with ringly --version or ringly update --check
(the latter prints a JSON snapshot with current, latest, hasUpdate,
reachable β handy for scripts and CI). The Claude Code plugin updates
automatically when a new version lands in the marketplace; force a manual
refresh with /plugin marketplace update if you want it now.
The check is throttled to one request per day, only hits the public npm
registry, and respects opt-out. To disable it, set check_updates: false by
running ringly config or editing ~/.claude/settings.json directly.
As of v0.5.0, Ringly is configured exclusively from the CLI. The
plugin.jsonno longer declares auserConfigblock, so Claude Code's/pluginβ Installed β Ringly β Configure screen does not appear by design. Read on for why.
Up to v0.4.x Ringly showed up in /plugin's native configuration UI. In
practice the UX was full of footguns that came from the manager itself, not
from our plugin:
- The
languagefield was a free-text input. The officialuserConfigschema (documented by Anthropic atcode.claude.com) only supportsstring/number/boolean/directory/fileβ no enum support. Users had to typept-BRoren-USletter-by-letter (with the dash) and a typo silently fell back toauto. Enteron a boolean does not toggle it. Inside the plugin manager,Enteronly confirms field navigation β you had to remember to pressSpaceto flip a boolean. Plenty of folks reported "I unchecked it and it was still on".- No visual validation, no atomic-write confirmation. The plugin manager
writes directly to
~/.claude/settings.jsonwith no explicit backup and no reminder to run/reload-plugins.
None of this is the Claude Code team's fault β userConfig is a deliberately
minimal schema that fits simple plugins (one URL, one token). For Ringly's
shape (enum language, seven toggles, "this fires OS notifications" context)
the bad UX outweighed the upside of a native screen.
The technical fix would be to ask Anthropic to add enum and Enter-toggle
to the schema. Until that lands, we chose to drop userConfig entirely
rather than pretend the experience is fine.
| Method | When to use |
|---|---|
ringly config β slick TUI in your terminal (β¨ recommended) |
Best experience: arrow keys to navigate, space to toggle, visual language picker. Writes into settings.json for you (atomic + timestamped backup) and reminds you to run /reload-plugins at the end. |
Edit settings.json directly |
Best for automation/CI. Keys live under pluginConfigs.ringly.options (see Available settings). Always run /reload-plugins after. |
ringly init |
Re-run the interactive installer (banner, AUMID register, full setup). Use it when reinstalling or if settings.json was wiped. |
If you search for Ringly under
/plugin β Installed, the plugin shows up there (it is installed β hooks are registered), but the Configure entry simply does not exist for Ringly. That's intentional, not a bug.
The hook dispatcher reads, in this priority order:
~/.claude/settings.jsonβpluginConfigs.ringly.optionsβ the only persistent source. Ringly reads this file directly at the start of every hook, so changes made byringly configapply immediately, with no restart required.- Environment variables
RINGLY_DEBUG=1andCLAUDE_PLUGIN_OPTION_*β volatile overrides.CLAUDE_PLUGIN_OPTION_*is still honoured as an optional override (useful to forcedebug=truefor a single shell without persisting anything), but Claude Code no longer exports anything on its own now thatuserConfigis gone. You have to set these env vars yourself if you want them. - Built-in defaults β final fallback.
The keys below live in pluginConfigs.ringly.options inside ~/.claude/settings.json. ringly config creates/edits all of them for you.
| Key | Type | Default | Description |
|---|---|---|---|
language |
auto / pt-BR / en-US |
auto |
Auto-detects from system locale when set to auto. |
events_notification |
boolean | true | Notify when Claude requests permission or input. |
events_stop |
boolean | true | Notify when Claude finishes a response. |
events_stopFailure |
boolean | true | Notify when an API error ends the session. |
events_subagentStop |
boolean | false | Notify when a subagent finishes. |
sound |
boolean | true | Play a sound with each notification. |
debug |
boolean | false | Write detailed logs. |
check_updates |
boolean | true | Check npm once a day at session start and notify via toast when a new version ships. |
ringly help # list the commands in the configured language
ringly init # interactive installer (TUI)
ringly init --non-interactive # apply defaults, skip the TUI
ringly config # reconfigure interactively
ringly doctor # run a diagnostic of the local setup
ringly test --event Stop --lang pt-BR
ringly update # check npm and run the guided update
ringly update --check # print {current, latest, hasUpdate, reachable, language, notes} JSON
ringly update --yes # skip the prompt and install directly
ringly uninstall # remove AUMID, shortcut, and Ringly settingsInside Claude Code, two slash commands cover the everyday flow:
/ringly-updateβ mirrorsringly update, with visual confirmation viaAskUserQuestion, a friendly summary of what changed in the new version (read from the packagedCHANGELOG.md), and an automatic prompt to run/reload-pluginsat the end. Everything shows up in the configured language./ringly-helpβ runsringly helpand shows the command list straight in the chat (with a warning that these commands must run in your external terminal, not inside Claude Code).
- Claude Code emits a hook event (
SessionStart,Notification,Stop,StopFailure,SubagentStop). - The plugin's
hooks.jsonrunsnode ${CLAUDE_PLUGIN_ROOT}/hooks/dispatch.mjs <Event>. dispatch.mjsreads~/.claude/settings.jsonand checks your Ringly options. If the event is disabled (events_*orcheck_updates), the dispatcher exits silently β nothing is fired.SessionStartfollows its own path: instead of becoming a toast directly, it triggers an npm version check (throttled to 24h) that only turns into a toast when a newer release is found.- If the event is enabled, the dispatcher reads the JSON payload from stdin and tries, in order:
- the
ringly/hookNode module β the normal path once the CLI has been installed (step 1 of the installation). Ships the richest translations and project-aware context. - the
ringlyCLI binary on PATH β used whenrequirecan't resolve the module but the CLI is installed globally. - an embedded PowerShell + WinRT fallback β last resort, only fires if
the two above failed. Because the
Claude.Code.CLIAUMID has to be registered byringly init, this fallback does not replace step 1: without the CLI it plays a beep at best and exits.
- the
- On Windows, the toast is generated as XML and shown via the registered
AUMID
Claude.Code.CLI. A beep is played as a fallback if Focus Assist or Do Not Disturb is blocking notifications.
- No toast appears: check Focus Assist or Do Not Disturb on Windows. Run
ringly doctorto inspect AUMID registration and notification permissions. - AUMID missing: re-run
ringly init --forceto recreate the Start Menu shortcut and re-register the application ID. - Hook seems silent: enable debug mode (
debug: truein the plugin config) and check the log file path printed byringly doctor.
Issues and pull requests are welcome. Read CONTRIBUTING.md
before opening a PR β it covers local setup, commit conventions, and how to run
the checks.
Release history: CHANGELOG.md.
Repository: github.com/nickdevcode/Ringly.