Controle de custo & segurança de secrets/extensões¶
Três ports nativos de coisas que o paperclip faz bem para dentro do harness do
Leopold: um hard-stop de budget em USD, um vault de secrets que mantém secrets fora
do prompt e gating de capabilities para extensões. Sem Postgres, sem daemon — estado
em .leopold/, secrets criptografados em disco, consentimento na CLI.
1. Hard-stop de budget em USD (driver SDK)¶
A CLI do Claude Code já reporta total_cost_usd por sessão, então não existe mapa de
preços de modelo: o driver acumula o custo real por item e para a run quando ele cruza
o teto.
Este é um teto opt-in, nunca o governador da run. Na cobrança por assinatura o
total_cost_usd não reflete a contabilidade real, então um contador em USD não pode
governar uma run autônoma — esse papel é do progresso durável (itens do plano
fechados) e dos tetos rígidos (max_iterations, max_windows, o gate de livelock —
veja Continuidade). O --budget-usd continua existindo para
usuários cobrados por API que querem um teto rígido em dólares; nunca é o padrão e
nada mais depende dele.
leopold-driver run --budget-usd 5(ouLEOPOLD_BUDGET_USD=5) define um teto de $5.worker.tslêtotal_cost_usddo eventoresult;loop.tsacumula emstate.spent_usde loga um eventocostpor item.- Aplicado no topo do loop (antes de cada item): quando
spent_usd >= budget_usd, a run para combudget_exceeded, notifica e deixa o trabalho em stage. - Funções de decisão puras (
parseBudgetUsd,overBudget) embudget.tstêm testes unitários.
2. Secrets fora do prompt (vault criptografado)¶
Hoje o worker é uma sessão crua do Claude Code, então qualquer secret que o trabalho
precisa tende a ser digitado no prompt/transcript. Isto injeta secrets como variáveis
de ambiente: elas chegam à tool Bash do worker como $NAME, mas nunca entram no prompt.
leopold-driver secrets set NAME(valor lido do stdin, então nunca cai no histórico do shell) criptografa em.leopold/secrets.env;secrets listmostra só os nomes.- Em repouso: AES-256-GCM. A master key de 32 bytes fica em
~/.claude/leopold/secrets.key(modo0600, gerada sob demanda); o vault é o blob criptografado. Chave errada/rotacionada → fail-closed (sem secrets). worker.tsdescriptografa o vault e coloca os valores emprocess.envpara o item (e os passa comooptions.env), restaurando o ambiente depois. O worker é instruído a usar$NAMEe nunca ecoar um valor.- A proteção é criptografia em repouso, não um guard de leitura: o vault é um blob
AES-256-GCM e a master key é
0600fora do projeto, então lersecrets.envrende ciphertext sem chave. O worker nunca precisa do arquivo — ele recebe os valores como$NAME.
3. Gating de capabilities para extensões¶
Uma extensão declara de antemão o que faz, e o menu do toolchain exige consentimento antes de conceder no install/update.
extension.jsonganha um arraycapabilities, ex. ovmem:["network", "settings.write", "filesystem.home", "package.install", "process.spawn"].leopold-menu.shmostra as capabilities declaradas na visão do componente, eInstall/Updateagora passam porext_consent— ele imprime as capabilities e exige umyantes de rodarmanage.sh install/update. Sem declaração → nada a liberar. As cinco extensões incluídas (leopold, serena, gstack, ovmem, enhance) declaram as suas.
Arquivos¶
| Área | Arquivos |
|---|---|
| Budget | packages/driver/src/{budget,config,loop,worker,types,index}.ts, test/budget.test.ts |
| Secrets | packages/driver/src/{secrets,worker,guard,index}.ts, hooks/guard-irreversible.sh, test/secrets.test.ts |
| Capabilities | extensions/*/extension.json, scripts/leopold-menu.sh |
Verificação¶
make driver-test(unitário): decisões de budget; round-trip de secret + criptografia em disco (sem plaintext) + chave0600+ apply/restore de env; a suíte do guard (só o lock de git commit/push).- Smoke de CLI:
secrets setvia stdin criptografa (sem plaintext no vault),secrets list, a chave é0600, nomes inválidos são rejeitados.leopold menumostra as capabilities e condiciona install/update ao consentimento. tsc --noEmitemake hooks-checkverdes.
Nota: budget e injeção de secrets miram o driver SDK (Path A), onde o driver controla o worker. O guard de bash continua protegendo os arquivos de secrets no caminho in-session.