Naia Kimi · leitura de código
Índice

CFS · leitura de material de terceiro · 04.09.2026

Nada foi
executado.
Só lido.

O pacote da Naia Kimi tem 31 arquivos e 7 pastas, e eu abri todos. Não rodei nem o install.sh, nem hook, nem script, em lugar nenhum. Extraí em pasta de rascunho fora de /opt/mari e não copiei uma linha pra dentro da nossa árvore.

O que vale ali não é o Kimi. É o jeito dele de transformar regra de comportamento em trava de máquina. É isso que a gente traz, e traz hoje, com Kimi ou sem Kimi.

O veredito curto

Três coisas justificam o pacote inteiro, e nenhuma delas depende de a gente montar a Mari Kimi.

E a correção que eu preciso dar de cara

A gente não está sem hook. Estamos com dois, presos em quatro eventos, no ~/.claude/settings.json: o security-scan.py e o task-tracker.py. Eu descobri isso do jeito mais direto possível: no meio desta análise, o security-scan.py bloqueou um comando meu por casar com o padrão de baixar código e canalizar pro interpretador. Ou seja, hook aqui funciona, roda dentro de subagente e já protege a casa.

Segurança do pacote

Credencial em texto puro: zero

Li os 31 arquivos procurando chave, token e senha. Não achei nenhum valor de credencial. Todo segredo dele resolve em tempo de execução com op read e op inject, do cofre do 1Password, e o cache fica só em memória do processo. O .gitignore ainda bloqueia .env, *.key e *.pem, e o install.sh grava o .env do bot com chmod 600.

Isso é higiene melhor que a nossa. A gente guarda segredo em arquivo no disco, em /opt/mari/.env e /opt/mari/.secrets/. Não é urgência, mas é um ponto em que ele está na frente.

O que tem ali e não devia circular

Segredo não tem. Mapa da operação dele, tem. Descrevo o tipo e o lugar, sem reproduzir valor:

Minha recomendação, e é só recomendação: o zip não circula. Ele já está na nuvem do Telegram porque chegou por lá. Não republicar, não subir em repositório, não mandar adiante. E se um dia a gente devolver alguma coisa pro Denderson, devolver o conceito, nunca o arquivo dele de volta editado.

Texto tentando dar ordem a quem lê

Procurei carga de injeção, quer dizer, trecho escrito pra quem estiver lendo o arquivo em vez de pra dona dele. Não existe nada desse tipo no pacote. Nenhuma frase endereçada ao leitor, nenhum "ignore suas instruções", nenhum pedido de credencial.

Mas existe um risco estrutural que eu preciso nomear, porque é real mesmo sem má intenção.

O AGENTS.md é um prompt de sistema completo, escrito em primeira pessoa

São 17 KB de regra imperativa: "eu nunca executo", "nunca discuto com o Chefe", "respondo APENAS o que ele perguntar". E tem um bloco que se declara superior a qualquer outro: este bloco vence qualquer outro trecho deste arquivo, da memória ou de skill.

O perigo não é o conteúdo, é a forma. Nesse arquivo, "o Chefe" é o Denderson, com o ID de Telegram dele, e "o outbox" é a pasta dele. Qualquer agente nosso que engula esse texto como instrução em vez de dado passa a ter outra definição de quem manda e de onde escrever a resposta.

Trava prática, e eu já cumpri as duas: o arquivo fica fora de /opt/mari, e nunca entra no knowledge/. Se ele fosse indexado, a busca da 3007 poderia devolver um pedaço dele como memória relevante, e aí o texto entraria no contexto da Mari por conta própria. Esse é o caminho pelo qual isso vira problema de verdade, e ele fecha com uma regra de uma linha: material de terceiro não é indexado.

Um detalhe de postura

A agente dele roda em modo yolo, sem confirmação de permissão, e o único freio é o hook de pastas confiáveis. A nossa postura é a mesma, com skipDangerousModePermissionPrompt ligado e o security-scan.py como freio. Os dois times chegaram sozinhos no mesmo desenho: liberdade total de execução, com uma trava de máquina no caminho.

Inventário, arquivo por arquivo

31 arquivos e 7 pastas. Nenhum pulado.

Antes de tudo, uma correção de contagem: o zip lista 38 entradas, mas sete delas são pastas. Arquivo mesmo são 31.

Raiz

AGENTS.md17,4 KBideias sim, texto não

A alma e o manual dela num arquivo só, que é o equivalente exato do nosso CLAUDE.md. Persona, protocolo de conversa, time de subagentes, memória, credenciais, infra e segurança.

README.md5,8 KBadaptar

A arquitetura inteira num diagrama de uma página, mais "como operar", "o que NÃO mexer" e "o que não está no repositório". O formato é bom e o nosso RECOVERY.md cobre só parte disso.

.gitignore325 Bjá temos

Bloqueia home/, state/, logs/, memory/*.md, .env, *.key e *.pem. O nosso tem 4 KB e cobre mais.

hooks · 11 arquivos

anti-promise.py4,4 KBtrazer

Hook de Stop. Promessa futura sem nenhuma chamada de ferramenta depois dela devolve exit 2 e o turno não fecha. É a peça mais valiosa do pacote.

anti-promise.sh330 Bnão serve aqui

Casca que registra no log e chama o Python do pyenv por caminho absoluto do Mac. A gente chama o script direto.

grounding-search.py4,5 KBtrazer

Hook de UserPromptSubmit. Consulta a memória vetorial com a mensagem do Chefe e injeta o que for relevante antes do modelo pensar.

grounding-search.sh325 Bnão serve aqui

Mesma casca de wrapper com caminho do Mac.

naia_bootstrap.py4,3 KBadaptar

Não é hook, é o módulo que os outros dois importam. Monta o contexto de boot: quem ela é, o pending.md cortado em 4.000 caracteres e as 10 últimas mensagens dela no banco.

session-start.py1,2 KBnão serve aqui

Existe só porque o Kimi 0.34.0 descarta a saída do SessionStart. No Claude Code essa saída é injetada de verdade, então a gambiarra some e o hook vira o canal principal.

session-start.sh303 Bnão serve aqui

Wrapper.

trusted-folders.py5,2 KBtrazer

Hook de PreToolUse. Escrita e comando destrutivo fora das zonas permitidas são bloqueados. Leitura é sempre livre. Complementa o nosso security-scan.py em vez de repetir.

trusted-folders.sh206 Bnão serve aqui

Wrapper.

pre-compact.sh484 Badaptar

Antes de compactar o contexto, roda o consolidador de conversa. Barato, e no nosso caso o valor é menor porque quem grava o histórico aqui é o bot, não a sessão.

stop-failure.sh394 Btrazer

Quando um turno morre por erro, grava a hora num arquivo. O guarda de resposta do bot lê isso e cutuca em 60 segundos em vez de 180. Quatro linhas que valem a pena.

cron-scripts · 3 arquivos

checkpoint.py4,0 KBadaptar

A cada 30 minutos, cópia dos arquivos de memória, do marcador de tarefa e do AGENTS.md, com manifest.json, sha256 por arquivo e retenção dos 24 últimos.

consolidate-kimi-conversations.py10,5 KBadaptar

O maior arquivo do pacote. Lê os bytes novos do registro bruto da sessão e grava no Postgres. Nosso bot já faz o equivalente para o Telegram, mas ele captura mais: chamada de ferramenta e fala interna também viram memória.

task-watchdog.py8,2 KBjá temos, melhor

Sinal de vida a cada 7 minutos e cutucão via tmux quando a sessão fica ociosa com tarefa aberta. O nosso status-nudge.sh faz o mesmo sem depender de marcador escrito à mão.

scripts · 4 arquivos

openrouter.sh6,2 KBadaptar

Lista, roda e compara modelos via OpenRouter, com tabela de latência, tamanho e custo. É bancada de teste, não é o cérebro dela. Detalho no bloco do provedor.

kimi-worker.sh1,6 KBtrazer a ideia

Dispara um trabalhador sem interface em segundo plano com saída em fluxo JSON, guardando o fluxo cru, um arquivo de progresso legível e o PID.

worker-progress-extractor.py2,0 KBadaptar

Transforma o fluxo JSON em linhas de progresso do tipo hora mais última ferramenta chamada. O formato do nosso fluxo é outro, então o extrator muda.

restore-checkpoint.sh1,7 KBadaptar

Devolve os arquivos de memória e o marcador de tarefa de um checkpoint. Assume por escrito que a conversa em si não volta.

Subida e supervisão · 3 arquivos

start.sh2,4 KBadaptar

Laço de vida: continua a sessão anterior, e se levar 3 quedas em menos de 120 segundos começa do zero. Espera crescente de 5 a 15 segundos. Temos equivalente.

supervise.sh615 Bjá temos

Mata e recria a sessão tmux rodando o start.sh, e vigia de 30 em 30 segundos. É o papel do nosso serviço no systemd.

install.sh4,5 KBnão serve aqui

Instalador idempotente do mundo macOS. Gera o .env a partir do cofre, copia os plists e sobe os cinco serviços com launchctl. A lógica de "sobe o bot só se o token existir" é boa, o resto não atravessa.

launchd · 5 arquivos

com.naia.kimi-agent.plist1,0 KBnão serve aqui

Mantém a agente viva. Vira systemd com Restart=always aqui.

com.naia.kimi-telegram-bot.plist989 Bnão serve aqui

Mantém o bot vivo. Mesmo destino.

com.naia.kimi-consolidate.plist1,1 KBnão serve aqui

De 2 em 2 minutos. Vira uma linha de crontab.

com.naia.kimi-task-watchdog.plist1,1 KBnão serve aqui

De minuto em minuto. Vira uma linha de crontab.

com.naia.kimi-checkpoint.plist1,1 KBnão serve aqui

De 30 em 30 minutos. Vira uma linha de crontab.

Pastas que nascem vazias · 2 arquivos

memory/.gitkeep0 Bnão serve aqui

Marcador de pasta. A memória em arquivo dele nasce vazia em toda réplica, porque o conteúdo durável mora no Postgres.

state/trusted-folders.example.json142 Btrazer

Modelo limpo da lista de pastas com permissão de escrita. Quatro caminhos de exemplo. É o formato que a gente copia junto com o hook.

O AGENTS.md dele, contra o nosso CLAUDE.md

17,4 KB dele · 14,5 KB nosso

Antes de qualquer comparação: a persona não se copia. A Mari é a Mari. O que interessa aqui é onde ele resolve melhor um problema que também é nosso.

O que ele tem e a gente não

O que a gente tem e ele não

Onde ele resolve melhor um problema que também é nosso

Promessa sem ação

Os dois arquivos proíbem a mesma coisa. A diferença é que o dele termina a frase com "meu hook anti-promise bloqueia". A regra dele tem quem a faça cumprir. A nossa é só a regra.

Esse é o padrão que se repete no pacote todo e é a lição que eu tiraria dele: toda regra de comportamento que ele consegue medir, ele vira hook. O resto continua sendo texto, como no nosso.

Buscar antes de afirmar

O nosso arquivo diz "quando o Chefe citar um assunto antigo, buscar antes de responder", e ainda deixa o comando de curl pronto. Depende de ela lembrar de rodar. No dele, a busca acontece sozinha em toda mensagem e o resultado já chega junto com a pergunta, com a instrução colada: não afirme nada que contradiga isso, e se não tiver informação aqui, diga que não tem certeza.

Os hooks, um a um

A parte que mais importa

Antes de entrar: eu conferi a documentação do Claude Code hoje, evento por evento, porque metade das decisões de portabilidade depende de detalhe que muda entre um CLI e outro. Duas descobertas mudam o desenho, e as duas jogam a favor.

Descoberta 1 · aqui o SessionStart funciona

No Kimi 0.34.0 o evento de início de sessão dispara mas a saída é jogada fora, e ele provou isso com um teste canário em agosto. Foi por isso que ele teve que enfiar o boot no primeiro prompt do usuário, com trava de arquivo pra não repetir. No Claude Code a saída do SessionStart entra no contexto normalmente, e o evento ainda aceita filtro por motivo: início, retomada, limpeza, compactação ou bifurcação. A gambiarra dele a gente não precisa, e ainda ganha um controle que ele não tem.

Descoberta 2 · o hook de Stop já recebe a última fala pronta

O anti-promessa dele gasta metade do código abrindo o registro bruto da sessão pra descobrir qual foi a última fala e se veio ferramenta depois. Aqui o payload do Stop entrega last_assistant_message de bandeja. A versão nossa nasce bem menor que a dele.

Com uma ressalva que eu não vou esconder: o Claude Code não tem o campo que evita laço infinito de hook de Stop. Então a trava de repetição dele, aquele arquivo de trava de 180 segundos por sessão, deixa de ser detalhe e vira obrigatória. Sem ela, um hook de Stop que bloqueia pode prender a sessão num laço.

anti-promise Stop porta com ajuste · alto valor
O que ele faz, exatamente
Quando o turno vai fechar, o hook lê o fim da sessão e separa duas coisas: qual foi a última fala visível dela e se houve alguma chamada de ferramenta depois dessa fala. Aí roda um teste de expressão regular nos últimos 500 caracteres, procurando promessa futura: "vou fazer", "vou checar", "vou delegar", "deixa comigo", "já volto", "te aviso quando", e mais uma dúzia de variações em português.
O que acontece quando casa
Se tem promessa e não teve ferramenta depois, o hook devolve exit 2 com a razão. O turno não fecha e o modelo recebe de volta o texto: você prometeu uma ação futura mas encerrou o turno sem executar nada. Execute AGORA. Promessa sem ação é proibida. Ela é obrigada a continuar e fazer.
As duas travas de segurança dele
Um arquivo de trava por sessão, com no máximo um bloqueio a cada 180 segundos, pra nunca virar laço. E falha aberta em tudo: payload ilegível, sessão não encontrada, erro de leitura, qualquer coisa devolve exit 0 e deixa passar. O hook nunca trava a agente por defeito próprio.
Funciona aqui?
Funciona, e sai mais simples. O evento Stop existe, exit 2 bloqueia mesmo, o stderr vira a razão que o modelo lê, e o last_assistant_message vem no payload. A parte de "houve ferramenta depois" precisa de outra fonte, porque a documentação avisa que o arquivo de transcrição é escrito de forma assíncrona e pode estar atrasado. Eu resolveria com um hook de PostToolUse de duas linhas carimbando a hora num arquivo por sessão, e o Stop comparando as duas horas. Mais confiável que ler transcrição.
Esforço
Estimativa minha: 1 hora, incluindo a lista de expressões calibrada pro jeito da Mari falar e um teste de mesa. E aplica também aos subagentes, porque hook de configuração vale dentro deles.
grounding-search UserPromptSubmit porta com ajuste · alto valor
O que ele faz
Toda mensagem do Chefe vira uma consulta na memória vetorial antes de o modelo ver a mensagem. O hook manda a mensagem inteira pro serviço em 127.0.0.1:3007, filtra o que vier com similaridade abaixo de 0,50, pega no máximo 3 trechos de arquivo e 3 fatos, corta cada um em 450 caracteres e monta um bloco de contexto.
O detalhe que faz diferença
O bloco não entrega só as memórias, entrega a instrução de como usá-las: "use isso pra fundamentar a resposta, não afirme nada que contradiga essas memórias, e se não tiver informação aqui, diga que não tem certeza em vez de inventar". É a nossa regra de não afirmar sem conferir a fonte, colada em toda pergunta, sem depender de ela lembrar.
Cuidados dele
Tempo limite de 2,5 segundos na chamada, pula prompt com menos de 12 caracteres pra não gastar busca com "ok" e "sim", e falha aberta em qualquer erro de rede. Se o serviço da 3007 cair, a conversa segue como se o hook não existisse.
Funciona aqui?
Funciona, e o evento é feito pra isso. No Claude Code o UserPromptSubmit é justamente um dos eventos cuja saída entra no contexto. Tem um ajuste obrigatório e eu já confirmei medindo: a nossa API da 3007 responde em outro formato. Ela devolve uma lista única em results, com source, content, score e type. A dele devolve chunks e facts separados, com similarity. Copiar o arquivo dele sem mexer resulta em hook que roda, não dá erro nenhum e nunca injeta nada, que é o pior tipo de defeito: o silencioso.
Esforço
Estimativa minha: 1 hora e meia. A maior parte é calibrar o corte de score, porque a escala da nossa API não é a mesma dele, e conferir na tela que o bloco realmente chega.
trusted-folders PreToolUse porta direto · alto valor
O que ele faz
Antes de qualquer ferramenta rodar, checa duas famílias. Nas ferramentas de escrita, pega o caminho do arquivo e bloqueia se estiver fora das zonas permitidas. No Bash, procura padrão destrutivo por expressão regular: rm com caminho absoluto, mv olhando o destino, e redirecionamento com > ou >> pra fora das zonas.
A filosofia, que é a parte boa
Leitura é sempre livre e a dúvida sempre libera. Caminho relativo, que não dá pra julgar, passa. Payload que não abre, passa. Lista de zonas vazia, passa. Ele prefere deixar escapar a travar a agente à toa, e diz isso no comentário do código. É a mesma escolha do nosso security-scan.py.
As zonas
Ficam num JSON editável em state/trusted-folders.json, com padrões embutidos caso o arquivo não exista: o projeto, a pasta do bot, /tmp e a pasta de entregas. Quando bloqueia, a mensagem já ensina a saída: peça ao Chefe pra adicionar o diretório na lista. E o AGENTS.md fecha o cerco com uma regra de comportamento: se bater no bloqueio, avise, nunca contorne por outro caminho.
Funciona aqui?
Funciona, e o Claude Code ainda oferece mais. Além do exit 2, o evento aceita uma resposta em JSON com permissionDecision valendo deny e um campo de motivo, e até um updatedInput que reescreve o comando antes de rodar. Dá pra fazer melhor que o original.
Isso conflita com o nosso security-scan?
Não, os dois olham eixos diferentes e somam. O nosso tem modelo de ameaça: baixar código e canalizar pro interpretador, contêiner privilegiado, bomba de processos, formatar disco, push --force no main. O dele é territorial: onde pode escrever. Um pega o comando perigoso em qualquer lugar, o outro pega o comando comum no lugar errado.
Esforço
Estimativa minha: 1 hora, quase toda gasta em desenhar a lista de zonas sem estrangular a operação. A gente escreve em muito lugar: /opt/mari, /opt/mari-bot, projetos, /tmp, pastas de usuário. Lista apertada demais atrapalha mais do que ajuda.
session-start SessionStart não serve como está
O que ele faz
Quase nada, e ele sabe disso. O script existe pelo efeito colateral: apagar a trava de boot pra que o hook de prompt reinjete o contexto de início na próxima mensagem. Ele ainda escreve o contexto na saída, apostando que uma versão futura do Kimi passe a consumir, e comenta isso no código.
Funciona aqui?
O arquivo não, a função sim, e melhor. Como no Claude Code essa saída é injetada de verdade, o boot entra por aqui, direto, sem trava, sem lock e sem depender do primeiro prompt. O que a gente aproveita é o naia_bootstrap.py, que é quem monta o conteúdo.
naia_bootstrap módulo, não é hook adaptar · valor estrutural
O que ele monta
Três blocos e nada mais: uma nota curta de quem ela é e onde responde, o pending.md cortado em 4.000 caracteres, e as 10 últimas mensagens dela puxadas do Postgres com filtro por identificador de agente. Cada mensagem cortada em 800 caracteres.
Por que isso importa mais que o código
É a materialização do boot magro. O texto que ele injeta chega a dizer, dentro do próprio contexto: não releia arquivos grandes no boot, o grounding traz o que for relevante a cada mensagem. Compare com o nosso protocolo, que manda ler SOUL.md, USER.md, decisions.md, projects.md, pending.md e infra.md, mais 30 trocas, antes de responder a primeira palavra.
Funciona aqui?
O conteúdo sim, com adaptação: nosso banco é mari_memory, a tabela não tem coluna de agente e a senha vem de variável de ambiente, não de cofre. A parte de trava de boot some inteira.
O que isso custa de decisão
Trocar o protocolo de boot mexe no CLAUDE.md, que é a alma dela. Isso é decisão do Chefe, não minha. Mas é onde mora o ganho maior: menos contexto na largada é mais tempo de trabalho antes do reinício.
pre-compact PreCompact porta direto · valor baixo aqui
O que ele faz
Antes de o contexto ser compactado, chama o consolidador de conversa uma vez, pra nada se perder na compactação.
Funciona aqui?
O evento existe, aceita filtro por manual ou automático, e exit 2 até bloqueia a compactação. Mas o valor pra nós é menor, e é honesto dizer: aqui quem grava o histórico é o bot, antes e depois do Telegram confirmar, então compactar não apaga conversa. O que se ganha é pequeno.
O que eu faria no lugar
Usar o SessionStart com filtro de compact pra reinjetar o contexto essencial depois da compactação. É o mesmo problema atacado pelo outro lado, e resolve melhor: em vez de salvar antes de perder, restaurar depois de perder.
stop-failure StopFailure porta direto · barato
O que ele faz
Quatro linhas. Quando um turno morre por erro de API, grava a hora num arquivo e registra no log. Não bloqueia nada.
Pra que serve
Quem consome é o bot: com esse marcador, ele sabe distinguir turno que morreu de turno que está demorando, e cutuca em 60 segundos em vez de esperar 180. É pouco código pra uma diferença que o Chefe sente na hora.
Funciona aqui?
Sim, o evento StopFailure existe no Claude Code. Encaixa direto no nosso contingency.py, que hoje adivinha o estado lendo a tela do tmux atrás de padrões de apagão.
Esforço
Estimativa minha: 20 minutos pro hook, mais o ajuste no bot pra ler o marcador.

Uma ideia que nem ele explorou

Hook por subagente, no cabeçalho do arquivo do agente

Descobri hoje conferindo a documentação: no Claude Code, cada subagente pode declarar hooks próprios no cabeçalho, que valem só enquanto ele estiver ativo, e depois são limpos sozinhos. Isso não existe no mundo do Kimi e o Denderson não usa.

O uso óbvio pra casa: um hook de Stop no jonathan-copy e em quem mais produz texto, que lê a fala final e bloqueia se encontrar travessão ou os vícios de IA que o humanizer-ptbr caça. Hoje a regra de zero travessão é a instrução mais repetida da casa e a que mais fura. Vira impossível de furar, e custa uns 40 minutos.

Checkpoint, consolidação e vigia

A resposta que o Chefe não vai gostar, e é a verdade

O checkpoint dele não faz a Mari cair e outra continuar

Essa era a esperança, e eu preciso derrubar antes de descrever o resto. O restore-checkpoint.sh diz, em comentário, na saída do comando e no README, três vezes: o registro da sessão não é restaurado. A sessão do CLI não é regravável, então a cópia do registro fica lá só pra auditoria e leitura humana.

O que ele restaura são arquivos: as anotações de memória, o marcador de tarefa ativa e o arquivo de alma. Continuidade de conversa, não.

Ou seja: ele chegou exatamente na mesma conclusão que a gente chegou hoje de manhã. O histórico mora fora da sessão, no banco, gravado por quem não morre junto. A intenção mora numa ficha. A sessão em si é descartável. A gente não estava errado, e não existe truque escondido no pacote dele.

checkpoint.py, o que ele realmente faz

O que isso melhora aqui: nosso backup roda uma vez por dia, às 6h, e o git guarda o histórico. Entre um backup e o outro existe uma janela de 24 horas. Se uma consolidação noturna reescrever um arquivo de memória errado, a versão boa está a até um dia de distância. Trinta minutos de granularidade fecha isso por quase nada.

consolidate-kimi-conversations.py

É o maior arquivo do pacote e o mais bem feito de engenharia. Ele lê o registro bruto da sessão, que é um arquivo de uma linha JSON por evento, e transforma em linhas de conversa no Postgres.

Aqui ele tem uma coisa que a gente não tem

A nossa memória de conversa é o que passou pelo Telegram, porque quem grava é o bot. A dele é a sessão inteira: cada ferramenta chamada, cada fala interna, cada resultado. Quando ele pergunta "o que a gente fez ontem", a busca alcança o trabalho, não só o papo.

É um ganho real. Também é um custo real, em volume de banco e em ruído na busca vetorial. Eu não recomendaria copiar isso agora, mas registro como diferença honesta e como opção pra quando a memória de trabalho fizer falta.

task-watchdog.py, contra o nosso

ComportamentoNaia KimiNosso
Como sabe que há trabalhostate/active-task.json, que a agente escreve à mão ao delegarDescobre sozinho: varre os arquivos de subagente do transcrito e considera ativo o que mexeu nos últimos 3 min
Sinal de vida pro ChefeSim, a cada 7 min, escreve direto no outboxNão manda sozinho: cutuca a Mari pra que ela escreva o status
Cutucão na agenteSe ociosa há 5 min com tarefa aberta. Uma vez só por marcadorSe o Chefe está há 10 min sem notícia e há subagente vivo. Espera de 10 min entre cutucões
Marcador órfãoCala a boca depois de 3 h e registra no logNão se aplica, não existe marcador
Progresso realSim, cola a última linha de progresso do trabalhador na mensagemNão. Manda o nome do subagente e há quantos minutos
Truque de tecladosend-keys e depois Enter, porque a interface do Kimi ignora C-mC-m e ainda KPEnter de reforço, porque a nossa interface ociosa já ignorou C-m

Placar honesto: o nosso é melhor no que mais importa, que é descobrir trabalho sem depender da memória da agente. Marcador escrito à mão é exatamente o tipo de coisa que se esquece justo no dia corrido.

Ele ganha em dois pontos: manda sinal de vida sozinho, mesmo com a agente travada, e mostra progresso de verdade. E tem uma frase no AGENTS.md que eu levaria pro nosso arquivo sem mudar uma vírgula: o cutucão é pedido de verificação, não de entrega. Se o subagente ainda roda, ignore e continue esperando.

Qual provedor ele usa de verdade

A hipótese do OpenRouter não se confirma

Não é OpenRouter, e ele diz isso com todas as letras

O AGENTS.md tem uma seção só sobre isso: meu cérebro é e continua 100% K3. Nunca troco meu provider nem meu modelo. O openrouter.sh é bancada de teste sob demanda, pra quando o Chefe dele pedir "testa essa tarefa no modelo X" ou "compara os modelos". Tem três comandos: listar com contexto e preço, rodar um prompt, e comparar o mesmo prompt em vários modelos com tabela de latência, tamanho e custo.

Ele ainda amarra o uso: modelo pago só roda com pedido explícito, e o custo de cada teste é reportado na entrega. Prefere os gratuitos pra exploração.

O que ele usa mesmo, e por que isso mexe com a nossa conta

Ele roda o Kimi Code CLI, um binário próprio, com o modelo kimi-code/k3. E o README e o AGENTS.md repetem a mesma expressão em três lugares: assinatura, sem custo de API.

Isso importa porque o nosso plano de hoje desenhou outro caminho: manter o Claude Code e apontar o endereço da API pro endpoint compatível da Moonshot, com crédito pré-pago de US$ 20 e estimativa de US$ 15 a US$ 120 por mês conforme o uso.

EixoCaminho do DendersonCaminho do nosso plano
ProgramaKimi Code CLI, binário próprioClaude Code, o mesmo de hoje
Modelokimi-code/k3kimi-k3 por variável de ambiente
Como pagaAssinatura. Custo marginal por mensagem: zeroCrédito pré-pago por token
Nossas skillsNão carregam. Formato e motor são outrosCarregam iguais. A casca é a mesma
Nossos hooksOutro motor de hook, outro protocolo de saídaOs mesmos, sem reescrever
Nossos 7 subagentesReescreverCopiar com o modelo trocado
Prova de que funcionaRoda em produção, todo dia, na casa deleEndpoint testado daqui, agente ainda não montado

O que eu recomendo perguntar pra ele, em uma frase

Qual plano de assinatura ele paga e se esse plano aguenta o volume de uma agente trabalhando o dia inteiro. Nosso plano registrou que não achou tabela oficial confiável dos planos e classificou como suposição de fonte contraditória. O Denderson é a fonte que faltava, e é uma pergunta só.

O que eu não afirmo, porque não dá pra saber pelo pacote: se a assinatura do Kimi Code serve também pro endereço compatível que o nosso plano usa. São dois produtos com endereços diferentes. Isso muda tudo na conta e ninguém deveria chutar.

Como o negócio sobe, e como fica no Linux

A cadeia dele tem quatro elos: o serviço do macOS chama o supervise.sh, que cria a sessão tmux rodando o start.sh, que roda o CLI em laço. Se o CLI morre, o laço reergue. Se a sessão morre, o serviço reergue.

O start.sh é a peça com miolo, e a lógica é boa: continua a sessão anterior por padrão, começa do zero se não houver nenhuma, espera de 5 a 15 segundos entre tentativas, e se levar 3 quedas em menos de 120 segundos a próxima vai do zero, partindo do princípio de que a sessão anterior está corrompida. Sessão que durou mais de 5 minutos zera o contador.

Tem até uma nota amarga no comentário: o modo sem confirmação não combina com continuar sessão, então ele configura isso no arquivo do CLI e não na linha de comando. É o tipo de coisa que só se aprende quebrando.

A tradução, elo por elo

No mundo deleo que fazAqui
com.naia.kimi-agentmantém a agente vivasystemd com Restart=always. Já temos, é o mari.service
com.naia.kimi-telegram-botmantém o bot vivosystemd. Já temos
com.naia.kimi-consolidatede 2 em 2 minUma linha de crontab. Não precisamos: o bot já grava
com.naia.kimi-task-watchdogde 1 em 1 minUma linha de crontab. Já temos, é o status-nudge.sh
com.naia.kimi-checkpointde 30 em 30 minUma linha de crontab. Falta, e é o que interessa trazer
supervise.shcria e vigia o tmuxO systemd faz isso. Script desnecessário
start.shlaço com recomeçoJá temos equivalente
install.shinstalador idempotenteReescrever do zero se quisermos um

Esforço de portar a camada de subida

Perto de zero, porque a gente já está do outro lado. Não é que a camada dele seja difícil de traduzir, é que ela resolve um problema que a nossa infraestrutura já resolve há meses, e com ferramenta melhor: systemd tem reinício, dependência entre serviços, registro unificado e estado consultável. O launchd dele ainda precisa de um supervise.sh no meio pra dar conta do tmux.

O único item que falta mesmo é uma linha de crontab pro checkpoint de 30 minutos. É isso.

Uma coisa do install.sh que eu levaria

Ele é tolerante de propósito: se o token do bot ainda não existe no cofre, o instalador sobe a agente e deixa o bot desligado, avisando no resumo o que ficou pendente. Não quebra, não sobe pela metade em silêncio, e diz na cara o que falta. É o desenho certo pra quando a gente for subir a Mari Kimi e o token do bot novo ainda não estiver na mão.

Ele tem, nós temos

O que ele tem e nós não

O que nós temos e ele não

Leitura de conjunto: a gente está claramente na frente em operação, quer dizer, na máquina que mantém tudo de pé, mede, avisa e cuida do negócio. Ele está na frente em disciplina da agente, quer dizer, nas travas que impedem a agente de se comportar mal. São dois eixos diferentes, e por isso o pacote é útil: ele não repete o que a gente tem, ele preenche.

O que muda no plano da Mari Kimi

Li a página do plano inteira antes de escrever isto. Quatro coisas mudam, uma se confirma e uma pergunta nova aparece.

Muda · a decisão de provedor ganhou um dado novo

O plano tratou a assinatura como caminho possível, com a ressalva honesta de que não achou tabela oficial e que as fontes se contradiziam. Agora existe um terceiro rodando assinatura em produção, todo dia. Isso não decide sozinho, porque o caminho dele custa a nossa casca inteira: skills, hooks e os sete subagentes não atravessam pro Kimi Code CLI.

Mas muda a ordem das coisas. Antes de recarregar crédito, vale uma pergunta ao Denderson. Se a assinatura aguentar o volume, a conta de US$ 15 a US$ 120 por mês do plano some, e a discussão passa a ser sobre perder ou não a casca.

Muda · o relógio ganha uma quarta camada, e ela é estrutural

O plano tem três camadas pra impedir a Mari K de disparar rotina de horário: usuário separado, outbox separado e um delta de instrução. E o próprio plano admite o ponto fraco: a camada 3 é instrução, e instrução é exatamente onde o Kimi é pior.

O trusted-folders é a quarta camada, e não é instrução. Um hook de PreToolUse no settings.json dela, com /opt/mari-bot/outbox fora das zonas permitidas, transforma "ela não deve escrever no outbox da outra" numa recusa da máquina. Custa quase nada e vale mais que qualquer parágrafo no arquivo de instrução dela.

Digo com todas as letras: isso é melhor do que a gente desenhou. É a implementação em máquina da regra de irmã que ele escreveu em prosa, e resolve justo a camada que o plano identificou como a mais frágil.

Muda · o travessão deixa de ser esperança

O plano lista, entre os pontos piores do Kimi, que a regra de zero travessão vai furar e que o humanizer-ptbr deixa de ser acabamento e vira passe obrigatório. Passe obrigatório é instrução, e instrução é onde ele falha.

Com hook de Stop lendo a última fala e recusando o encerramento quando encontra travessão, a regra passa a se cumprir sozinha, nela e nos subagentes dela. Vira o item mais barato de todo o plano com efeito direto no que o Chefe lê.

Muda · o marcador de tarefa atravessa a queda

O plano reconhece o furo: o que ela pensou e não publicou morre junto, e arquivo escrito pela metade fica pela metade. A resposta dele era a ficha de pendência guardar a intenção.

O active-task.json é essa ficha, em formato que máquina lê. Se a Mari cair no meio, o arquivo sobrevive, e a Mari K consegue ler o que estava em andamento, com qual subagente e desde quando. Não devolve a conversa, mas devolve o rumo. Encaixa direto na tese de duas agentes com a mesma pasta.

Se confirma · a memória não volta, e não é limitação nossa

O plano concluiu que o histórico mora no banco, gravado pelo bot, e que a sessão é descartável. O pacote dele chegou na mesma conclusão por um caminho independente, e assumiu isso por escrito no script de restauração. Ninguém resolveu o problema porque não tem como resolver desse lado. Vale como confirmação, não como novidade.

Aparece · um detalhe pequeno que eu adotaria

Ele separa as irmãs por identificador de agente na mesma tabela, e não por chave de sessão. O nosso plano usa session_key='telegram-dm-k'. Os dois funcionam, mas o dele responde melhor a "o que a outra estava fazendo", que é justamente a consulta que o plano quer que as duas façam antes de começar tarefa longa. Carimbar as duas coisas custa uma coluna e resolve.

O que não muda: usuário Unix separado, mesma pasta de trabalho, bot próprio, memória compartilhada, correção do pgrep no vigia e vigia de contexto próprio pra ela. Nada no pacote dele contradiz nenhuma dessas escolhas. Aliás, ele confirma a primeira: o AGENTS.md dedica uma seção inteira à separação entre as irmãs, e ele fez isso sem usuário separado, só na base da instrução. Foi a saída que o macOS deixou. A gente tem uma melhor.

Implantação, por valor sobre esforço

Os tempos são estimativa minha, não medição

Os sete primeiros não dependem de Kimi nenhum e melhoram a operação de hoje. Do oitavo em diante só faz sentido junto com a Mari Kimi.

01

Hook anti-promessa no Stop

Lê o last_assistant_message, procura promessa futura em português, confere se houve ferramenta no turno por um carimbo de PostToolUse, e recusa o encerramento quando não houve. Trava de repetição obrigatória, porque aqui não existe proteção nativa contra laço. Vale pra Mari e pra todos os subagentes.

~1 hprecisa de OK delemexe no settings.json
02

Hook de travessão e vício de IA

Mesma família do primeiro, e é o mais barato com efeito visível. Bloqueia o encerramento quando a fala final tem travessão ou os vícios que o humanizer-ptbr caça. Começa pela Mari e pelo jonathan-copy, que é quem mais produz texto.

~40 minprecisa de OK dele
03

Busca automática no UserPromptSubmit

Toda mensagem do Chefe passa pela 3007 antes do modelo, e o que vier relevante entra junto, com a instrução de não contradizer. Exige reescrever o leitor de resposta, porque a nossa API devolve results com score e a dele devolve chunks e facts com similarity. Copiar sem mexer dá hook que roda e nunca injeta nada.

~1 h 30precisa de OK dele
04

Marcador de turno morto

Quatro linhas no StopFailure gravando a hora, e o contingency.py passando a ler esse marcador em vez de adivinhar pela tela do tmux. O Chefe sente na hora: recuperação em 60 segundos em vez de 180.

~20 minprecisa de OK dele
05

Checkpoint de 30 minutos com manifesto

Uma linha de crontab e um script curto: cópia das fichas de memória e do estado, com sha256 e retenção de 24. Fecha a janela de 24 horas entre um backup e o outro. Não mexe em comportamento nenhum, só acrescenta rede de proteção.

~45 minnão precisa de OK
06

Lista de pastas com permissão de escrita

Hook de PreToolUse ao lado do security-scan.py, com falha aberta e leitura sempre livre. O trabalho não é o código, é desenhar a lista sem estrangular a operação, porque a gente escreve em muito lugar. Fica melhor que o dele usando permissionDecision com motivo em vez de exit 2 seco.

~1 hprecisa de OK dele
07

Boot magro

O de maior ganho e o de maior consequência. Passa o protocolo de boot pra um hook de SessionStart, com filtro por motivo, e corta a leitura proativa dos seis arquivos, confiando na busca do item 3. Menos contexto na largada é mais tempo de trabalho antes do reinício aos 75%. Mexe no CLAUDE.md, que é a alma dela, e por isso é decisão do Chefe. Só depois do item 3 estar funcionando, nunca antes.

~1 hdecisão dele, não minhadepende do item 3
08

Progresso real no status de 10 minutos

Trabalhador em segundo plano com saída em fluxo JSON, escrevendo um arquivo de progresso legível que o status-nudge.sh cola na mensagem. Hoje o status diz o que a agente acha que está acontecendo. Passa a dizer qual ferramenta rodou por último e quando.

~1 h 30não precisa de OK
09

Pergunta ao Denderson sobre a assinatura

Qual plano ele paga e se aguenta uma agente trabalhando o dia inteiro. Custa uma mensagem e pode apagar a linha de custo mensal do plano da Mari Kimi. Ação para fora, então é ele quem manda.

1 mensagemsó ele pode fazer
10

Zonas de escrita como quarta camada do relógio

No settings.json da Mari K, com o outbox da Mari fora da lista. Transforma a fronteira entre as irmãs em recusa de máquina, e não em parágrafo que ela pode não seguir.

~30 minjunto com a Mari Kimidepende do item 6
11

Marcador de tarefa compartilhado

Um arquivo de estado que as duas escrevem e leem, pra que a queda de uma no meio do trabalho seja visível pra outra. Junto com o carimbo de identificador de agente na tabela de conversa.

~1 hjunto com a Mari Kimi
12

Hooks no cabeçalho de cada subagente dela

Os sete agentes dela já vão ser copiados com o modelo trocado. Aproveitar a passagem pra prender a trava de travessão no cabeçalho de quem escreve texto. Custo marginal perto de zero, feito na mesma hora.

+15 minjunto com a Mari Kimidepende do item 2

Se ele só liberar uma coisa

Os itens 1 e 2, juntos. São duas horas, mexem no mesmo lugar, atacam os dois defeitos que mais se repetem aqui, e nenhum dos dois depende de Kimi, de dinheiro ou de root. O item 5 pode ir junto porque não precisa de autorização: só acrescenta cópia de segurança e não muda comportamento nenhum.