⚡ AutomationsAI|Portal de Cursos →

Verificando acesso...

MÓDULO 3.3

👥 Multi-usuário e multi-tenancy

Rode 1 instância de Hermes para família, time ou pequena empresa, isolando memórias, skills e API keys por pessoa. Sem vazamento entre usuários, sem custo duplicado, com auditoria.

6
Tópicos
~45
Minutos
Inter.
Nível
Avançado
Tipo
1

👤 Modelo de usuário — Como o Hermes separa contextos

O Hermes usa um conceito de tenant (=usuário lógico) que carrega ID, namespace de memória, profile e quota. Toda mensagem entra pelo router de canal, é resolvida para um tenant e aí tudo — memória, skills, secrets, logs — fica escopado a ele.

Diagrama: 1 instância → N usuários → N namespaces

                    ┌──────────────────────────┐
                    │   Hermes Agent (1 proc)  │
                    │  port 7777, PID 14523    │
                    └─────────────┬────────────┘
                                  │
        ┌─────────────────────────┼─────────────────────────┐
        │                         │                         │
   ┌────▼────┐              ┌─────▼────┐              ┌─────▼────┐
   │ tenant: │              │ tenant:  │              │ tenant:  │
   │  alice  │              │  bob     │              │  carol   │
   │ (mãe)   │              │ (filho)  │              │ (pai)    │
   └────┬────┘              └─────┬────┘              └─────┬────┘
        │                         │                         │
   ┌────▼────────┐         ┌──────▼──────┐          ┌───────▼─────┐
   │ memory/     │         │ memory/     │          │ memory/     │
   │   alice.db  │         │   bob.db    │          │   carol.db  │
   │ skills/alice│         │ skills/bob  │          │ skills/carol│
   │ secrets:    │         │ secrets:    │          │ secrets:    │
   │  OR_KEY_A   │         │  OR_KEY_B   │          │  OR_KEY_C   │
   │ quota: $20  │         │ quota: $5   │          │ quota: $50  │
   └─────────────┘         └─────────────┘          └─────────────┘

💡 Resolução de tenant

Toda mensagem que chega num canal passa por tenant_resolver. A ordem padrão:

  • 1.Match exato em users.<canal>.<id> no config
  • 2.Fallback pra tenant default (se permitido)
  • 3.Rejeição com mensagem "user not authorized" (se strict_users: true)

Feature × tipo de isolamento

Feature Isolamento Onde mora
Histórico de chatTotal~/.hermes/memory/<tenant>.db
Memória semânticaTotal~/.hermes/embeddings/<tenant>/
API keys (OpenRouter etc)TotalKeyring + secrets/<tenant>.enc
Skills privadasTotalskills/<tenant>/
Skills compartilhadasCompartilhadoskills/shared/
Modelo / providerOverride por userprofiles/<tenant>.toml
Logs de auditoriaCompartilhado (tagged)logs/audit.jsonl
2

🔑 API keys por usuário — OpenRouter sub-keys ou múltiplas

Você tem 3 caminhos, do mais simples ao mais escalável. A escolha errada vira factura inflada no fim do mês.

A

1 chave master + limite por user (mais barato)

Você mantém UMA sk-or-... da conta principal e o Hermes aplica quota.monthly_usd por tenant.

Bom pra: família, equipe <5 pessoas, confiança alta.

B

OpenRouter sub-keys (recomendado)

Em openrouter.ai/settings/keys crie 1 sub-key por pessoa, com limite mensal próprio. Isolamento de verdade — fatura mostra gasto por chave.

Bom pra: time, clientes, qualquer ambiente com auditoria.

C

Cada usuário traz a própria chave (BYOK)

Cada pessoa cria conta no OpenRouter e cadastra a chave dela via hermes user secrets set. Você não paga nada além do hosting.

Bom pra: SaaS interno, instalação compartilhada open source.

Comando real — cadastrando chave por user

# Cria tenant
hermes user create alice --display "Alice Maldaner" --quota 20.00

# Cadastra chave da Alice (vai pro keyring com namespace dela)
hermes user secrets set alice OPENROUTER_API_KEY sk-or-v1-alice-************

# Override de modelo padrão só pra Alice
hermes user config set alice model.default "anthropic/claude-sonnet-4.5"

# Lista
hermes user list
  NAME    QUOTA     USED   MODEL                          STATUS
  alice   $20.00   $3.42   anthropic/claude-sonnet-4.5    active
  bob     $5.00    $0.18   meta-llama/llama-3.3-70b:free  active
  carol   $50.00   $47.10  openai/gpt-4o                  ⚠ near-limit

✓ FAZER

  • Sub-keys OpenRouter por pessoa (B)
  • Quota mensal hard no Hermes E no provider
  • Rotacionar chaves a cada 90 dias
  • Alertar usuário em 80% da quota

✗ NÃO fazer

  • 1 chave compartilhada sem quota — fatura explode
  • Salvar chaves em .env versionado
  • Confiar só em quota local (sem limite no provider)
  • Reusar chave entre prod e dev
3

💾 Memória isolada — DB por usuário ou namespace

Hermes oferece dois modos de isolar memória. Escolha errado e a Alice recebe lembrança de conversa do Bob — vazamento clássico em multi-tenancy.

📦 DB por usuário (default, seguro)

Cada tenant tem arquivo SQLite próprio. Impossível query cruzar.

~/.hermes/memory/ alice.db bob.db carol.db

Pro: zero risco. Contra: difícil migrar/agregar.

🏷️ DB único + namespace

Tudo num hermes.db, toda query tem WHERE tenant_id = ?.

SELECT * FROM messages WHERE tenant_id = 'alice' ORDER BY ts DESC;

Pro: backup único, escala melhor. Contra: bug no WHERE = vazamento.

Configurando o modo

# ~/.hermes/config.toml
[memory]
mode = "per_user"          # ou "namespaced"
path = "~/.hermes/memory"
backend = "sqlite"         # sqlite | postgres | duckdb
auto_vacuum = true
encryption = "age"         # opcional, criptografa em repouso

[memory.semantic]
enabled = true
embeddings_model = "text-embedding-3-small"
per_user_index = true      # NUNCA false em multi-tenant

⚠️ Vazamento entre usuários

O bug #1 em setups multi-user é per_user_index = false na memória semântica. O retrieval traz embeddings de TODOS os tenants — a Alice pergunta "onde guardei a senha do banco" e recebe a senha do Bob. Sempre teste:

hermes audit leak-check --tenant alice ✓ memory.sqlite: isolated ✓ memory.embeddings: isolated ✓ skills.private: isolated ✗ logs.shared: tagged but globally readable (expected)

💡 Dica — backup seletivo

Com DB por usuário, backup vira cp alice.db alice.db.bak. Você consegue dar pra Alice o backup só da memória dela quando ela pedir, sem expor dados dos outros. Compliance amigável.

4

🧩 Skills compartilhadas vs privadas — Estratégias

Skills (tools, prompts especializados, fluxos) podem ser globais (todos veem) ou privadas (só dono usa). Saber dividir reduz duplicação e vazamento.

Layout de diretórios

~/.hermes/skills/
├── shared/                  # disponível a TODOS os tenants
│   ├── web-search/
│   ├── calculator/
│   └── translate-ptbr/
├── alice/                   # só Alice vê
│   ├── meu-banco-api/       # tem credenciais privadas
│   └── agenda-trabalho/
├── bob/                     # só Bob vê
│   └── jogos-steam/
└── disabled/                # tirou de circulação sem deletar
    └── legacy-thing/

Comandos de gerência

# Instala skill compartilhada (acessível a todos)
hermes skill install https://github.com/foo/web-search --scope shared

# Instala skill privada da Alice
hermes skill install ./meu-banco-api --scope user --user alice

# Promove de privada pra compartilhada
hermes skill promote alice/agenda-trabalho --to shared

# Lista skills visíveis pra cada user
hermes skill list --user alice
  SCOPE    NAME                SOURCE
  shared   web-search          github.com/foo/web-search
  shared   calculator          builtin
  user     meu-banco-api       local
  user     agenda-trabalho     local

# Audita o que cada skill acessa
hermes skill audit alice/meu-banco-api
  Network calls: api.meubanco.com.br
  Filesystem:    read ~/.hermes/secrets/alice/banco.enc
  Subprocess:    none
  Tokens used:   BANCO_TOKEN (encrypted, alice-only)

✓ Compartilhar quando

  • Skill é genérica (web search, calculadora)
  • Não tem credenciais embutidas
  • Output é seguro pra qualquer audiência
  • Você quer evitar 3 cópias idênticas

✗ NUNCA compartilhar

  • Skills com token de banco/email pessoal
  • Skills que escrevem em path pessoal
  • Skills com prompt que vaza identidade
  • Skills experimentais que podem crashar
5

📊 Quotas e budget por usuário — Limites práticos

Sem quota, um único filho perguntando "explica detalhadamente toda física quântica" zera o budget familiar. Hermes tem 3 níveis de limite: tokens/dia, custo/mês e rate.

Config completa de família (4 pessoas, real)

# ~/.hermes/config.toml

[multitenancy]
enabled = true
strict_users = true              # rejeita ID não cadastrado
default_tenant = false           # sem fallback inseguro

[users.alice]              # mãe - power user
display = "Alice"
quota = { monthly_usd = 30.0, daily_tokens = 500000, rate_per_min = 30 }
model_default = "anthropic/claude-sonnet-4.5"
secrets_namespace = "alice"
channels = { telegram = [123456789], discord = ["alice#0001"] }

[users.bob]                # filho 14 anos - limitado
display = "Bob"
quota = { monthly_usd = 5.0, daily_tokens = 100000, rate_per_min = 10 }
model_default = "meta-llama/llama-3.3-70b-instruct:free"
secrets_namespace = "bob"
channels = { telegram = [987654321] }
content_filter = "strict"        # bloqueia NSFW

[users.carol]              # pai - corporativo
display = "Carol"
quota = { monthly_usd = 50.0, daily_tokens = 1000000, rate_per_min = 60 }
model_default = "openai/gpt-4o"
secrets_namespace = "carol"
channels = { slack = ["U12345"], telegram = [555444333] }

[users.daniel]             # filha 8 anos - kid mode
display = "Daniel"
quota = { monthly_usd = 2.0, daily_tokens = 30000, rate_per_min = 5 }
model_default = "anthropic/claude-haiku-4.5"
content_filter = "kids"
channels = { telegram = [111222333] }

[quota.alerts]
warn_at_pct = 80                 # avisa user em 80%
hard_stop_at_pct = 100           # corta acesso em 100%
notify_admin = "alice"           # quem recebe alerta

Setup família 4 pessoas — timeline

1

Min 0-5 · Cria os 4 tenants

Para cada um: hermes user create <nome> --quota X

2

Min 5-15 · Sub-keys OpenRouter

openrouter.ai/settings/keys → 4 sub-keys com limite. hermes user secrets set <u> OPENROUTER_API_KEY ...

3

Min 15-25 · Pega chat_id de cada um

Cada pessoa abre @userinfobot no Telegram, manda o ID pra você, você adiciona em channels.telegram.

4

Min 25-35 · Bot único no Telegram

hermes channel start telegram — o bot resolve cada chat_id para o tenant correto automaticamente.

5

Min 35-45 · Teste e audit

hermes audit leak-check --all-tenants + cada pessoa manda "oi, qual meu nome?" e confirma a resposta certa.

📊 Dashboard de uso

Rode hermes usage --month e veja consumo por user:

USER TOKENS_IN TOKENS_OUT COST_USD REQUESTS MODEL_TOP alice 1,240,512 382,109 $12.40 412 claude-sonnet-4.5 bob 92,103 14,221 $0.18 89 llama-3.3-70b:free carol 3,012,440 980,331 $47.10 203 gpt-4o daniel 22,310 4,012 $0.42 54 claude-haiku-4.5
6

🚪 Roteamento por canal — Telegram chat_id, Discord user_id

Cada canal entrega um identificador próprio. O tenant resolver mapeia esse ID externo → tenant interno. Errar isso = mensagem da Alice cai no contexto do Bob.

Identificadores por canal

Canal ID estável Como obter
Telegramchat_id (int)@userinfobot
Discorduser.id (snowflake)Dev Mode ON → click direito → "Copiar ID"
Slackuser_id (U...)Perfil → Mais → "Copiar member ID"
CLI (TUI)$USER do SOwhoami
HTTP APIHeader X-Hermes-TenantCliente envia explicitamente

Config do roteador

# ~/.hermes/config.toml — bloco de routing

[router]
strategy = "exact_match"   # exact_match | regex | callback
unknown_action = "deny"    # deny | default_tenant | prompt_admin

[router.telegram]
# chat_id -> tenant
mapping = {
  123456789 = "alice",
  987654321 = "bob",
  555444333 = "carol",
  111222333 = "daniel"
}

[router.discord]
mapping = {
  "281234567890123456" = "alice",
  "291234567890123456" = "bob"
}

[router.slack]
mapping = {
  "U01ABCDE" = "carol"     # só Carol usa Slack
}

# Caso especial: grupo no Telegram com vários users
[router.telegram.groups]
"-1001234567890" = "carol"   # grupo "Trabalho", tudo cai no tenant carol

📊 Como testar o roteamento

  • hermes route test telegram 123456789 → mostra qual tenant resolveria
  • hermes route trace --tail → loga em tempo real toda resolução
  • hermes audit cross-tenant-msgs --last 7d → detecta se algo escapou pro tenant errado

⚠️ Grupo do Telegram = caso ESPECIAL

Em group chat o chat_id é do GRUPO, não da pessoa. Se mapear pro tenant errado, todo mundo no grupo vira "aquela pessoa". Decida: ou força from_user.id como chave (cada um tem contexto próprio), ou aceita que o grupo todo é UM tenant (contexto compartilhado). Configure com router.telegram.group_strategy = "per_user" | "shared".

💡 Dica — auditoria contínua

Adicione hermes audit weekly-report --email admin@familia.local no cron. Toda sexta você recebe: gastos por user, top skills usadas, alertas de quota, anomalias de roteamento, vazamentos suspeitos. 10 minutos pra prevenir 10 horas de bagunça.

Resumo do Módulo

Modelo de tenant

1 instância, N usuários, cada um com namespace próprio

API keys isoladas

Sub-keys OpenRouter por pessoa com limite no provider

Memória sem vazamento

per_user DB + per_user_index nos embeddings

Skills bem divididas

Genéricas compartilhadas, com credencial sempre privadas

Quotas em 3 níveis

tokens/dia, custo/mês, rate/min — com alerta em 80%

Roteador testado

hermes route test + audit cross-tenant-msgs

Próximo módulo:

3.4 — 🚨 Troubleshooting de setup — Top 20 erros: sintoma → diagnóstico → fix.