Nofax
Aprovações e notificações com intervenção humana para agentes de codificação de IA por meio de um servidor MCP local e hooks de agente.
Documentação
Nofax
Aprovações e notificações com intervenção humana para agentes de IA, sem executar um SaaS Nofax.
Nofax é uma pequena ponte open-source entre um agente e um humano. O modo local pode pausar um fluxo de trabalho de IA, notificar seu telefone e retornar uma decisão explícita. Um Cloudflare Worker opcional, auto-implantado, expõe uma superfície MCP remota deliberadamente mais restrita para notificações unidirecionais e inspeção segura de solicitações.
Sem conta Nofax. Sem API de modelo paga. Sem porta de entrada no seu computador. Licença MIT.
Status atual: o Nofax local é
0.2.1. O Cloudflare Worker opcional é a próxima superfície remota0.3.0e é desenvolvido em conjunto com o pacote local.
Por que Nofax
Os fluxos de trabalho de agentes precisam cada vez mais de uma resposta clara para uma pergunta: quando a automação atinge um limite de decisão humana, como ela pergunta sem fingir que o silêncio significa aprovação?
Nofax mantém esse limite explícito:
- pendente nunca é aprovação;
- timeout e falha de transporte falham de forma segura (fail closed);
- a primeira resposta terminal aceita vence;
- esquemas de hooks específicos de agentes permanecem isolados em adaptadores;
- o acesso remoto é intencionalmente mais restrito que o acesso local;
- Nofax não concede autoridade que o agente chamador já não possuía.
Dois modos de operação
| Capacidade | Nofax local 0.2 | Worker remoto 0.3 |
|---|---|---|
| Transporte | stdio / hooks CLI | MCP Streamable HTTP |
| Notificação unidirecional | Sim | Sim |
| Permitir / Negar | Sim | Não |
| Escolhas explícitas | Sim | Não |
| Refinamento de texto livre | Sim | Não |
| Aguardar resposta humana | Sim | Não |
| Ler metadados da solicitação | Sim | Sim |
| Estado durável | Arquivos locais | Linhas existentes do SQLite Durable Object |
| Hospedado pela Nofax | Não | Não — Worker auto-implantado |
| Autenticação remota | Limite do processo local | Chave bearer privada |
O Worker remoto não é um serviço de aprovação remota hospedado. Ele pode enviar uma notificação informativa e inspecionar o estado existente da solicitação, mas não possui callback de aprovação, escolha, refinamento, espera, webhook ou endpoint arbitrário de escrita remota.
Início rápido
1. Instalar
npm install -g nofax
Requer Node.js 20 ou mais recente.
2. Inicializar
nofax init
Nofax cria ~/.nofax/config.json e gera um tópico de notificação de alta entropia. Com o transporte padrão, assine o tópico exibido no aplicativo móvel ntfy.
3. Testar
nofax test
4. Usar
nofax notify --title "Build finished" "All tests passed"
nofax approve --title "Deploy?" "Release 1.4.0 is ready"
nofax refine --title "Refine draft" "Tell me what to change"
Uma aprovação resolve para JSON terminal estável:
{"decision":"allow"}
ou:
{"decision":"deny"}
Se a solicitação ainda estiver pendente, expirar, desconectar ou encontrar um erro de transporte, Nofax nunca converte essa condição em aprovação.
MCP
Inicie o servidor MCP stdio local:
nofax mcp
O MCP local expõe:
nofax_notifynofax_request_approvalnofax_request_choicenofax_request_refinementnofax_wait_for_responsenofax_get_requestnofax_list_pending
Solicitações interativas retornam um ID de solicitação durável. nofax_wait_for_response realiza uma espera limitada; os chamadores devem repetir a espera enquanto a solicitação permanecer pendente, em vez de inferir aprovação.
Integrações de agentes
Claude Code
Use Nofax como um hook local PermissionRequest em ~/.claude/settings.json:
{
"hooks": {
"PermissionRequest": [
{
"matcher": ".*",
"hooks": [
{
"type": "command",
"command": "nofax hook claude"
}
]
}
]
}
}
Codex
Os hooks do Codex estão habilitados por padrão. Configure ~/.codex/hooks.json:
{
"hooks": {
"PermissionRequest": [
{
"matcher": ".*",
"hooks": [
{
"type": "command",
"command": "nofax hook codex",
"statusMessage": "Waiting for Nofax approval"
}
]
}
]
}
}
Reinicie o Codex, execute /hooks e revise/confie na definição exata do hook Nofax antes de depender dele. O Codex ignora hooks não gerenciados até que sejam confiáveis, e uma definição de hook alterada deve ser revisada novamente. Se um administrador ou política local desabilitou explicitamente os hooks, reabilite-os com [features] hooks = true em ~/.codex/config.toml.
Gemini CLI
As versões atuais do Gemini CLI expõem um hook síncrono BeforeTool que pode permitir ou negar uma chamada de ferramenta. Roteie ferramentas selecionadas através do Nofax em ~/.gemini/settings.json:
{
"hooks": {
"BeforeTool": [
{
"matcher": "run_shell_command|write_file|replace",
"hooks": [
{
"name": "nofax-approval",
"type": "command",
"command": "nofax hook gemini",
"timeout": 305000
}
]
}
],
"Notification": [
{
"matcher": "ToolPermission",
"hooks": [
{
"name": "nofax-notification",
"type": "command",
"command": "nofax hook gemini"
}
]
}
]
}
}
BeforeTool aguarda um resultado explícito de Permitir/Negar do Nofax. Um timeout ou falha de transporte do Nofax emite JSON válido de não-decisão e deixa o fluxo de política/confirmação do próprio Gemini CLI no controle, em vez de converter falha em aprovação. O hook Notification permanece consultivo e é encaminhado apenas como notificação telefônica.
Ajuste o matcher para as ferramentas que você deseja que o Nofax controle. Mantenha o timeout do hook maior que o timeout de aprovação configurado do Nofax (timeoutSeconds, 300 segundos por padrão).
Cloudflare Worker remoto opcional
O pacote worker/ fornece um endpoint MCP privado e auto-implantado:
remote MCP client
|
| authenticated Streamable HTTP
v
Cloudflare Worker
|
+--> nofax_notify ------> ntfy ------> phone
|
+--> SQLite Durable Object
|
+--> get request metadata
+--> list pending requests
Ele expõe exatamente três ferramentas:
nofax_notify— notificação unidirecional apenas;nofax_get_request— lê uma projeção segura de solicitação;nofax_list_pending— lê projeções de solicitações não resolvidas e não expiradas.
Implante a partir de worker/:
npm ci
npx wrangler login
npx wrangler secret put NOFAX_REMOTE_KEY
npx wrangler secret put NTFY_TOPIC
npm run check
npm run deploy
Conexão MCP preferida:
https://<worker>.workers.dev/mcp
Authorization: Bearer <NOFAX_REMOTE_KEY>
Clientes que não podem anexar um cabeçalho de autorização estático podem usar o caminho de capacidade de compatibilidade:
https://<worker>.workers.dev/mcp/<NOFAX_REMOTE_KEY>
Trate a URL de capacidade completa como uma senha.
Consulte docs/remote-mcp.md para detalhes de implantação, limites de ameaça e qualificação.
Importante: ntfy público + egress sem servidor
O serviço público padrão ntfy.sh aplica cotas de publicador. Plataformas sem servidor, como Cloudflare Workers, podem usar espaço de IP de saída compartilhado, então um Worker pode receber uma resposta de cota diária 42908 do ntfy mesmo quando esse Worker individual enviou muito pouco tráfego. Esse limite é imposto pelo ntfy, não pela cota de solicitações do Cloudflare Workers.
Para implantações sensíveis à confiabilidade, use um provedor de notificação cuja cota esteja vinculada à sua própria conta/identidade autenticada, ou opere um transporte auto-hospedado confiável. Não construa um fluxo de trabalho crítico em torno de suposições de cota de tópico público anônimo.
Modelo de segurança
Nofax é um componente de transporte e interação humana, não um mecanismo de política de autorização.
Modo local:
- pendente, timeout, desconexão, estado malformado e falha de rede nunca significam aprovação;
- a primeira resposta terminal válida vence;
- tópicos de notificação e tópicos de resposta única são capacidades;
- ntfy público não é criptografado de ponta a ponta pelo provedor;
- a redação é melhor esforço e não pode identificar de forma confiável segredos embutidos em texto livre arbitrário.
Modo remoto:
- apenas
nofax_notifyexplícito realiza um efeito colateral de mensagens externas; - operações de inspeção de solicitação são somente leitura e não realizam gravações de limpeza ocultas;
- superfícies de aprovação remota, callback, webhook, refinamento, escolha e espera estão ausentes;
NOFAX_REMOTE_KEYé uma credencial bearer;- projeções remotas omitem capacidades de callback, texto de prompt/mensagem e listas internas de decisões permitidas.
Leia SECURITY.md antes de usar Nofax com informações sensíveis.
Configuração
A configuração local padrão está em ~/.nofax/config.json:
{
"version": 1,
"server": "https://ntfy.sh",
"topic": "nofax_<random>",
"timeoutSeconds": 300
}
Substitua o diretório inicial com NOFAX_HOME:
NOFAX_HOME=/path/to/nofax-home nofax config
Use outro servidor compatível com ntfy com:
nofax init --server https://ntfy.example.com --force
Desenvolvimento
Pacote local:
npm ci
npm run check
npm test
npm pack --dry-run
Worker remoto:
cd worker
npm ci
npm run check
O CI qualifica Node.js 20, 22 e 24 para o pacote local. O gate do Worker executa TypeScript, Vitest, uma auditoria de dependências de produção e um dry-run de implantação do Wrangler.
Documentação do projeto
docs/architecture.md— limites de confiança e fluxo de dadosdocs/remote-mcp.md— implantação e qualificação do Worker remotoSECURITY.md— premissas de segurança e relato de vulnerabilidadesCONTRIBUTING.md— expectativas de contribuição e testesCHANGELOG.md— histórico de versões
Não-objetivos
Nofax deliberadamente não fornece:
- um SaaS de aprovação operado pela Nofax;
- uma dependência de API de modelo paga;
- política persistente
always approve; - um endpoint remoto arbitrário de shell;
- um Worker multi-usuário público atrás de uma chave de implantação compartilhada;
- uma alegação de que anotações MCP por si só são um limite de segurança.
Licença
MIT © Tomi Šeregi. Consulte LICENSE.