> ## Documentation Index
> Fetch the complete documentation index at: https://chatcli.edilsonfreitas.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploy com Docker e Kubernetes

> Como fazer deploy do ChatCLI como servidor usando Docker, Docker Compose ou Helm no Kubernetes.

O ChatCLI pode ser empacotado como container Docker e deployado no Kubernetes usando o Helm chart oficial. Esta página cobre todos os cenários de deployment.

***

## Imagens Oficiais (GHCR)

As imagens Docker oficiais são publicadas automaticamente no GitHub Container Registry a cada release:

<CardGroup cols={2}>
  <Card title="Servidor ChatCLI" icon="server">
    **Última versão: 1.152.0** <br />
    `ghcr.io/diillson/chatcli:1.152.0`
  </Card>

  <Card title="Kubernetes Operator" icon="dharmachakra">
    **Última versão: 1.152.0** <br />
    `ghcr.io/diillson/chatcli-operator:1.152.0`
  </Card>
</CardGroup>

```bash theme={"system"}
# Puxar a imagem do servidor (versão específica — recomendado)
docker pull ghcr.io/diillson/chatcli:1.152.0

# Ou a última versão disponível
docker pull ghcr.io/diillson/chatcli:latest

# Puxar a imagem do operator
docker pull ghcr.io/diillson/chatcli-operator:1.152.0
```

<Info>
  As imagens suportam **multi-arch** (`linux/amd64` e `linux/arm64`).
</Info>

***

## Docker

### Build da Imagem (Local)

```bash theme={"system"}
# Na raiz do projeto
docker build -t chatcli .
```

O Dockerfile usa multi-stage build para produzir uma imagem mínima (\~20MB):

* **Build stage**: `golang:1.25-alpine` compila o binário
* **Runtime stage**: `alpine:3.21` com usuário não-root, health check integrado

### Build da Imagem do Operator (Local)

```bash theme={"system"}
# IMPORTANTE: deve ser construído a partir da raiz do repositório
# (go.mod do operator usa replace directive apontando para ../)
docker build -f operator/Dockerfile -t ghcr.io/diillson/chatcli-operator:latest .
```

O Dockerfile do operator usa:

* **Build stage**: `golang:1.25` com suporte multi-arch (`TARGETARCH`)
* **Runtime stage**: `gcr.io/distroless/static:nonroot` (segurança máxima, sem shell)

### Rodar com Docker

<Tabs>
  <Tab title="Básico">
    ```bash theme={"system"}
    docker run -p 50051:50051 \
      -e LLM_PROVIDER=OPENAI \
      -e OPENAI_API_KEY=sk-xxx \
      chatcli
    ```
  </Tab>

  <Tab title="Com Auth">
    ```bash theme={"system"}
    docker run -p 50051:50051 \
      -e CHATCLI_SERVER_TOKEN=meu-token \
      -e LLM_PROVIDER=CLAUDEAI \
      -e ANTHROPIC_API_KEY=sk-ant-xxx \
      chatcli
    ```
  </Tab>

  <Tab title="Com Persistência">
    ```bash theme={"system"}
    docker run -p 50051:50051 \
      -v chatcli-sessions:/home/chatcli/.chatcli/sessions \
      -e LLM_PROVIDER=OPENAI \
      -e OPENAI_API_KEY=sk-xxx \
      chatcli
    ```
  </Tab>
</Tabs>

### Docker Compose

O projeto inclui um `docker-compose.yml` pronto para desenvolvimento:

<Steps>
  <Step title="Defina as variáveis">
    ```bash theme={"system"}
    export LLM_PROVIDER=OPENAI
    export OPENAI_API_KEY=sk-xxx
    ```
  </Step>

  <Step title="Inicie o container">
    ```bash theme={"system"}
    docker compose up -d
    ```
  </Step>

  <Step title="Conecte do seu terminal">
    ```bash theme={"system"}
    chatcli connect localhost:50051
    ```
  </Step>
</Steps>

O Docker Compose configura:

* Porta 50051 exposta
* Volumes persistentes para sessões e plugins
* Restart automático (`unless-stopped`)
* Todas as variáveis de LLM via environment
* **Hardening de segurança**: filesystem read-only, `no-new-privileges`, limites de CPU/memória, tmpfs para `/tmp`

#### Arquivo `docker-compose.yml`

```yaml theme={"system"}
version: "3.9"

services:
  chatcli-server:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: chatcli-server
    ports:
      - "50051:50051"
    environment:
      CHATCLI_SERVER_PORT: "50051"
      CHATCLI_SERVER_TOKEN: "${CHATCLI_SERVER_TOKEN:-}"
      LLM_PROVIDER: "${LLM_PROVIDER:-}"
      OPENAI_API_KEY: "${OPENAI_API_KEY:-}"
      ANTHROPIC_API_KEY: "${ANTHROPIC_API_KEY:-}"
      GOOGLEAI_API_KEY: "${GOOGLEAI_API_KEY:-}"
      OLLAMA_ENABLED: "${OLLAMA_ENABLED:-}"
      OLLAMA_BASE_URL: "${OLLAMA_BASE_URL:-}"
      GITHUB_COPILOT_TOKEN: "${GITHUB_COPILOT_TOKEN:-}"
      COPILOT_MODEL: "${COPILOT_MODEL:-}"
      OPENROUTER_API_KEY: "${OPENROUTER_API_KEY:-}"
      LOG_LEVEL: "${LOG_LEVEL:-info}"
    volumes:
      - chatcli-sessions:/home/chatcli/.chatcli/sessions
      - chatcli-plugins:/home/chatcli/.chatcli/plugins
    restart: unless-stopped
    read_only: true
    tmpfs:
      - /tmp:size=100M
    security_opt:
      - no-new-privileges:true
    deploy:
      resources:
        limits:
          cpus: "2.0"
          memory: 1G

volumes:
  chatcli-sessions:
  chatcli-plugins:
```

> O container roda com filesystem **read-only** e `no-new-privileges` por padrão. O diretório `/tmp` usa tmpfs em memória (limitado a 100MB). Os volumes nomeados (`chatcli-sessions`, `chatcli-plugins`) são os únicos pontos graváveis. Veja a [documentação de segurança](/pt/features/security) para detalhes.

***

## Kubernetes (Helm)

Os Helm charts do ChatCLI estão disponíveis como **artefatos OCI no GHCR** — não é necessário clonar o repositório.

### Pré-requisitos

* Cluster Kubernetes (kind, minikube, EKS, GKE, AKS, etc.)
* Helm 3.8+ instalado (suporte a OCI)
* `kubectl` configurado para o cluster

### Instalação Básica

<Tabs>
  <Tab title="OpenAI">
    ```bash theme={"system"}
    helm install chatcli oci://ghcr.io/diillson/charts/chatcli \
      --set llm.provider=OPENAI \
      --set secrets.openaiApiKey=sk-xxx
    ```
  </Tab>

  <Tab title="Anthropic (com Auth)">
    ```bash theme={"system"}
    helm install chatcli oci://ghcr.io/diillson/charts/chatcli \
      --set llm.provider=CLAUDEAI \
      --set secrets.anthropicApiKey=sk-ant-xxx \
      --set server.token=meu-token-secreto
    ```
  </Tab>
</Tabs>

<Note>
  Se preferir usar o chart local (após clonar o repo), substitua `oci://ghcr.io/diillson/charts/chatcli` por `./deploy/helm/chatcli/` em todos os comandos abaixo.
</Note>

### Instalação com Segurança (Helm)

Para deployments com segurança completa, incluindo rate limiting, autenticação JWT e modo agente seguro:

```bash theme={"system"}
helm install chatcli oci://ghcr.io/diillson/charts/chatcli \
  --set security.rateLimitRps=20 \
  --set security.agentSecurityMode=strict \
  --set security.jwtSecretRef.name=chatcli-jwt \
  --set security.jwtSecretRef.key=secret
```

### Instalação com K8s Watcher (Single-Target)

```bash theme={"system"}
helm install chatcli oci://ghcr.io/diillson/charts/chatcli \
  --set llm.provider=OPENAI \
  --set secrets.openaiApiKey=sk-xxx \
  --set watcher.enabled=true \
  --set watcher.deployment=myapp \
  --set watcher.namespace=production
```

### Instalação com Multi-Target + Prometheus

Para monitorar múltiplos deployments com métricas Prometheus, use um `values.yaml`:

```yaml theme={"system"}
# values-multi.yaml
llm:
  provider: CLAUDEAI
secrets:
  anthropicApiKey: sk-ant-xxx
watcher:
  enabled: true
  interval: "15s"
  maxContextChars: 32000
  targets:
    - deployment: api-gateway
      namespace: production
      metricsPort: 9090
      metricsFilter: ["http_requests_*", "http_request_duration_*"]
    - deployment: auth-service
      namespace: production
      metricsPort: 9090
    - deployment: worker
      namespace: batch
```

```bash theme={"system"}
helm install chatcli oci://ghcr.io/diillson/charts/chatcli -f values-multi.yaml
```

O chart automaticamente:

* Cria ServiceAccount com RBAC para o watcher ler pods, eventos, logs
* **Auto-detecta multi-namespace**: se targets estão em namespaces diferentes, usa `ClusterRole` em vez de `Role`
* Gera ConfigMap `<name>-watch-config` com o YAML multi-target
* Monta o config como volume e passa `--watch-config` ao container
* Passa corretamente as flags `--token`, `--model` e `--mcp-config` ao servidor
* Usa **health probes gRPC nativas** (liveness, readiness e startup) em vez de `pidof`
* Inclui todos os **17 CRDs do operator** no diretório `crds/`

### Valores do Helm Chart

#### Servidor

| Valor                     | Descrição                                             | Padrão                     |
| ------------------------- | ----------------------------------------------------- | -------------------------- |
| `replicaCount`            | Número de réplicas                                    | `1`                        |
| `image.repository`        | Repositório da imagem                                 | `ghcr.io/diillson/chatcli` |
| `image.tag`               | Tag da imagem                                         | `latest`                   |
| `server.port`             | Porta gRPC                                            | `50051`                    |
| `server.metricsPort`      | Porta HTTP para Prometheus metrics (0 = desabilitado) | `9090`                     |
| `server.token`            | Token de autenticação                                 | `""`                       |
| `server.grpcReflection`   | Habilitar gRPC reflection (debugging)                 | `false`                    |
| `serviceMonitor.enabled`  | Criar ServiceMonitor (requer Prometheus Operator)     | `false`                    |
| `serviceMonitor.interval` | Intervalo de scrape do Prometheus                     | `30s`                      |

#### TLS

| Valor                | Descrição                  | Padrão  |
| -------------------- | -------------------------- | ------- |
| `tls.enabled`        | Habilitar TLS              | `false` |
| `tls.certFile`       | Caminho do certificado     | `""`    |
| `tls.keyFile`        | Caminho da chave           | `""`    |
| `tls.existingSecret` | Secret existente com certs | `""`    |

#### LLM

| Valor          | Descrição       | Padrão |
| -------------- | --------------- | ------ |
| `llm.provider` | Provedor padrão | `""`   |
| `llm.model`    | Modelo padrão   | `""`   |

#### Secrets (API Keys)

| Valor                        | Descrição                                  |
| ---------------------------- | ------------------------------------------ |
| `secrets.existingSecret`     | Secret existente (em vez de criar um novo) |
| `secrets.openaiApiKey`       | Chave da OpenAI                            |
| `secrets.anthropicApiKey`    | Chave da Anthropic                         |
| `secrets.googleaiApiKey`     | Chave do Google AI                         |
| `secrets.xaiApiKey`          | Chave da xAI                               |
| `secrets.openrouterApiKey`   | Chave do OpenRouter                        |
| `secrets.stackspotClientId`  | StackSpot Client ID                        |
| `secrets.stackspotClientKey` | StackSpot Client Key                       |
| `secrets.stackspotRealm`     | StackSpot Realm                            |
| `secrets.stackspotAgentId`   | StackSpot Agent ID                         |
| `secrets.githubCopilotToken` | Token OAuth do GitHub Copilot              |

#### GitHub Copilot

| Valor                  | Descrição                                                  | Padrão                          |
| ---------------------- | ---------------------------------------------------------- | ------------------------------- |
| `COPILOT_MODEL`        | Modelo padrão do Copilot (ex: `gpt-4o`, `claude-sonnet-4`) | `gpt-4o`                        |
| `COPILOT_MAX_TOKENS`   | Máximo de tokens para resposta                             | `""`                            |
| `COPILOT_API_BASE_URL` | URL base da API (para ambientes enterprise)                | `https://api.githubcopilot.com` |

> Para autenticação, use `secrets.githubCopilotToken` com um token obtido via `/auth login github-copilot`, ou defina `GITHUB_COPILOT_TOKEN` como variável de ambiente.

#### Ollama

| Valor            | Descrição          | Padrão                |
| ---------------- | ------------------ | --------------------- |
| `ollama.enabled` | Habilitar Ollama   | `false`               |
| `ollama.baseUrl` | URL base do Ollama | `http://ollama:11434` |
| `ollama.model`   | Modelo Ollama      | `""`                  |

#### K8s Watcher

| Valor                     | Descrição                                      | Padrão  |
| ------------------------- | ---------------------------------------------- | ------- |
| `watcher.enabled`         | Habilitar o watcher                            | `false` |
| `watcher.targets`         | Lista de targets multi-deployment (ver abaixo) | `[]`    |
| `watcher.deployment`      | Deployment único - legado                      | `""`    |
| `watcher.namespace`       | Namespace do deployment - legado               | `""`    |
| `watcher.interval`        | Intervalo de coleta                            | `30s`   |
| `watcher.window`          | Janela de observação                           | `2h`    |
| `watcher.maxLogLines`     | Linhas de log por pod                          | `100`   |
| `watcher.maxContextChars` | Budget de contexto LLM                         | `32000` |

**Campos de cada target** (`watcher.targets[].`):

| Campo           | Descrição                           |    Obrigatório   |
| --------------- | ----------------------------------- | :--------------: |
| `deployment`    | Nome do deployment                  |        Sim       |
| `namespace`     | Namespace (padrão: `default`)       |        Não       |
| `metricsPort`   | Porta Prometheus (0 = desabilitado) |        Não       |
| `metricsPath`   | Path HTTP das métricas              | Não (`/metrics`) |
| `metricsFilter` | Filtros glob para métricas          |        Não       |

#### Fallback de Provedores

| Valor                   | Descrição                                      | Padrão  |
| ----------------------- | ---------------------------------------------- | ------- |
| `fallback.enabled`      | Habilitar cadeia de failover automático        | `false` |
| `fallback.providers`    | Lista ordenada de provedores `[{name, model}]` | `[]`    |
| `fallback.maxRetries`   | Tentativas por provedor antes de avançar       | `2`     |
| `fallback.cooldownBase` | Cooldown base após falha                       | `30s`   |
| `fallback.cooldownMax`  | Cooldown máximo (backoff exponencial)          | `5m`    |

#### MCP (Model Context Protocol)

| Valor                   | Descrição                                                                  | Padrão  |
| ----------------------- | -------------------------------------------------------------------------- | ------- |
| `mcp.enabled`           | Habilitar integração MCP                                                   | `false` |
| `mcp.servers`           | Lista de servidores MCP `[{name, transport, command, args, url, enabled}]` | `[]`    |
| `mcp.existingConfigMap` | ConfigMap existente com `mcp_servers.json`                                 | `""`    |

#### Bootstrap e Memória

| Valor                         | Descrição                                            | Padrão  |
| ----------------------------- | ---------------------------------------------------- | ------- |
| `bootstrap.enabled`           | Carregar arquivos bootstrap (SOUL.md, USER.md, etc.) | `false` |
| `bootstrap.definitions`       | Definições inline de arquivos bootstrap              | `{}`    |
| `bootstrap.existingConfigMap` | ConfigMap existente com arquivos bootstrap           | `""`    |
| `memory.enabled`              | Habilitar memória persistente                        | `false` |
| `safety.enabled`              | Habilitar regras de segurança configuráveis          | `false` |

#### Skill Registry

| Valor                           | Descrição                                                 | Padrão  |
| ------------------------------- | --------------------------------------------------------- | ------- |
| `skillRegistry.enabled`         | Habilitar variáveis de ambiente para skill registry       | `false` |
| `skillRegistry.registryUrls`    | URLs adicionais de registries (separadas por vírgula)     | `""`    |
| `skillRegistry.registryDisable` | Nomes de registries a desabilitar (separados por vírgula) | `""`    |
| `skillRegistry.installDir`      | Diretório de instalação de skills dentro do container     | `""`    |

> Quando habilitado, os valores são passados como variáveis `CHATCLI_REGISTRY_*` no ConfigMap. O container ChatCLI cria automaticamente `~/.chatcli/registries.yaml` com os registries padrão (chatcli, clawhub). Use `/skill search` e `/skill install` para gerenciar skills via registries.

#### Persistência

| Valor                      | Descrição                | Padrão |
| -------------------------- | ------------------------ | ------ |
| `persistence.enabled`      | Persistir sessões em PVC | `true` |
| `persistence.storageClass` | Storage class            | `""`   |
| `persistence.size`         | Tamanho do volume        | `1Gi`  |

#### Segurança

| Valor                                      | Descrição                                       | Padrão           |
| ------------------------------------------ | ----------------------------------------------- | ---------------- |
| `podSecurityContext.runAsNonRoot`          | Obriga execução como não-root                   | `true`           |
| `podSecurityContext.runAsUser`             | UID do processo                                 | `1000`           |
| `podSecurityContext.seccompProfile.type`   | Perfil seccomp                                  | `RuntimeDefault` |
| `securityContext.allowPrivilegeEscalation` | Permite escalação de privilégios                | `false`          |
| `securityContext.readOnlyRootFilesystem`   | Filesystem somente-leitura                      | `true`           |
| `securityContext.capabilities.drop`        | Capabilities removidas                          | `ALL`            |
| `rbac.clusterWide`                         | Usa ClusterRole em vez de Role namespace-scoped | `false`          |

> Quando `readOnlyRootFilesystem` está `true`, o chart monta automaticamente um tmpfs em `/tmp` e um emptyDir em `/home/chatcli/.chatcli` (200Mi) para dados de runtime. A variável `HOME=/home/chatcli` é definida automaticamente. Para monitorar múltiplos namespaces, habilite `rbac.clusterWide: true`. Veja a [documentação de segurança](/pt/features/security) para detalhes.
>
> **Nota**: O ConfigMap e o Secret referenciados via `envFrom` são marcados como `optional: true`, permitindo criar o Instance/Deployment antes dos recursos dependentes. O operator observa Secrets automaticamente e dispara rolling updates quando são criados ou atualizados.

#### Autoscaling (HPA)

| Valor                                           | Descrição                         | Padrão  |
| ----------------------------------------------- | --------------------------------- | ------- |
| `autoscaling.enabled`                           | Habilitar HorizontalPodAutoscaler | `false` |
| `autoscaling.minReplicas`                       | Mínimo de réplicas                | `1`     |
| `autoscaling.maxReplicas`                       | Máximo de réplicas                | `10`    |
| `autoscaling.targetCPUUtilizationPercentage`    | Meta de uso de CPU (%)            | `80`    |
| `autoscaling.targetMemoryUtilizationPercentage` | Meta de uso de memória (%)        | `""`    |

> Quando `autoscaling.enabled` é `true`, o `replicaCount` é ignorado e o HPA controla o número de réplicas automaticamente.

#### Pod Disruption Budget

| Valor                                | Descrição                                                 | Padrão  |
| ------------------------------------ | --------------------------------------------------------- | ------- |
| `podDisruptionBudget.enabled`        | Criar PodDisruptionBudget                                 | `false` |
| `podDisruptionBudget.minAvailable`   | Mínimo de pods disponíveis durante disruptions            | `1`     |
| `podDisruptionBudget.maxUnavailable` | Máximo de pods indisponíveis (alternativa a minAvailable) | `""`    |

> O PDB garante alta disponibilidade durante upgrades de nó, drain e manutenção do cluster.

#### Network Policy

| Valor                            | Descrição                    | Padrão  |
| -------------------------------- | ---------------------------- | ------- |
| `networkPolicy.enabled`          | Criar NetworkPolicy          | `false` |
| `networkPolicy.allowIngressFrom` | Regras de ingress permitidas | `[]`    |
| `networkPolicy.allowEgressTo`    | Regras de egress permitidas  | `[]`    |

> A NetworkPolicy restringe tráfego de rede no nível do pod. Requer um CNI com suporte a NetworkPolicy (Calico, Cilium, etc.).

#### Rede

| Valor              | Descrição                                                                                             | Padrão      |
| ------------------ | ----------------------------------------------------------------------------------------------------- | ----------- |
| `service.type`     | Tipo do Service                                                                                       | `ClusterIP` |
| `service.port`     | Porta do Service                                                                                      | `50051`     |
| `service.headless` | Habilita Service headless para balanceamento gRPC client-side (recomendado quando `replicaCount > 1`) | `false`     |
| `ingress.enabled`  | Habilitar Ingress                                                                                     | `false`     |

> **gRPC e múltiplas réplicas**: O gRPC usa conexões HTTP/2 persistentes que fixam em um único pod. Para `replicaCount > 1`, habilite `service.headless: true` para ativar balanceamento round-robin via DNS. O client já possui keepalive e round-robin integrados.
>
> **Ingress gRPC**: Quando o Ingress está habilitado com `className: nginx`, o chart adiciona automaticamente a annotation `nginx.ingress.kubernetes.io/backend-protocol: "GRPC"` para rotear tráfego gRPC corretamente.

### Usando Secret Existente

Se você já tem um Secret com as API keys:

```bash theme={"system"}
helm install chatcli oci://ghcr.io/diillson/charts/chatcli \
  --set llm.provider=OPENAI \
  --set secrets.existingSecret=my-llm-keys
```

O Secret deve conter as chaves esperadas:

```yaml theme={"system"}
apiVersion: v1
kind: Secret
metadata:
  name: my-llm-keys
type: Opaque
stringData:
  OPENAI_API_KEY: "sk-xxx"
  ANTHROPIC_API_KEY: "sk-ant-xxx"
  OPENROUTER_API_KEY: "sk-or-xxx"  # opcional
  GITHUB_COPILOT_TOKEN: "ghu_xxx"  # opcional
```

### Acessar o Servidor

<Tabs>
  <Tab title="Port Forward (Dev)">
    ```bash theme={"system"}
    kubectl port-forward svc/chatcli 50051:50051
    chatcli connect localhost:50051
    ```
  </Tab>

  <Tab title="NodePort">
    ```bash theme={"system"}
    helm install chatcli oci://ghcr.io/diillson/charts/chatcli \
      --set service.type=NodePort
    chatcli connect <node-ip>:<node-port>
    ```
  </Tab>

  <Tab title="LoadBalancer">
    ```bash theme={"system"}
    helm install chatcli oci://ghcr.io/diillson/charts/chatcli \
      --set service.type=LoadBalancer

    # Aguarde o IP externo
    kubectl get svc chatcli -w
    chatcli connect <external-ip>:50051
    ```
  </Tab>
</Tabs>

#### Ingress (com TLS)

```yaml theme={"system"}
# values-prod.yaml
ingress:
  enabled: true
  className: nginx
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  hosts:
    - host: chatcli.meudominio.com
      paths:
        - path: /
          pathType: ImplementationSpecific
  tls:
    - secretName: chatcli-tls
      hosts:
        - chatcli.meudominio.com
```

```bash theme={"system"}
helm install chatcli oci://ghcr.io/diillson/charts/chatcli -f values-prod.yaml
```

### Upgrade e Rollback

```bash theme={"system"}
# Atualizar
helm upgrade chatcli oci://ghcr.io/diillson/charts/chatcli --set llm.model=gpt-4-turbo

# Rollback
helm rollback chatcli 1
```

***

## Configuração de Segurança

O Helm chart suporta configuração de segurança avançada para ambientes de produção:

| Valor                        | Descrição                                                                                         | Padrão                        |
| ---------------------------- | ------------------------------------------------------------------------------------------------- | ----------------------------- |
| `security.rateLimitRps`      | Limite de requisições por segundo (rate limiting)                                                 | `0` (desabilitado)            |
| `security.bindAddress`       | Endereço de bind do servidor. Auto-detecta `0.0.0.0` em Kubernetes via `KUBERNETES_SERVICE_HOST`. | `127.0.0.1` / `0.0.0.0` (K8s) |
| `security.agentSecurityMode` | Modo de segurança do agente (`strict` ou `permissive`)                                            | `strict`                      |
| `security.jwtSecretRef.name` | Nome do Secret Kubernetes contendo o segredo JWT                                                  | `""`                          |
| `security.jwtSecretRef.key`  | Chave dentro do Secret com o valor do segredo JWT                                                 | `""`                          |
| `security.auditLog`          | Habilitar log de auditoria de segurança                                                           | `false`                       |
| `security.sessionEncryption` | Habilitar criptografia de sessões em repouso                                                      | `false`                       |

```yaml theme={"system"}
# values-security.yaml
security:
  rateLimitRps: 20
  # bindAddress: "0.0.0.0"  # Opcional — auto-detectado em Kubernetes
  agentSecurityMode: strict
  auditLog: true
  sessionEncryption: true
  jwtSecretRef:
    name: chatcli-jwt
    key: secret
```

<Note>
  Em Kubernetes, o `bindAddress` é automaticamente detectado como `0.0.0.0` via a variável de ambiente `KUBERNETES_SERVICE_HOST`. Não é necessário configurar manualmente.
</Note>

<Warning>
  Em produção, sempre configure `security.jwtSecretRef` para habilitar autenticação JWT. Sem isso, o servidor aceita conexões sem autenticação.
</Warning>

***

## Exemplo Completo: Produção

### Single-Target (Legado)

```bash theme={"system"}
helm install chatcli oci://ghcr.io/diillson/charts/chatcli \
  --namespace chatcli --create-namespace \
  --set llm.provider=CLAUDEAI \
  --set secrets.anthropicApiKey=sk-ant-xxx \
  --set server.token=super-secret-token \
  --set tls.enabled=true \
  --set tls.existingSecret=chatcli-tls-certs \
  --set watcher.enabled=true \
  --set watcher.deployment=production-app \
  --set watcher.namespace=production \
  --set persistence.enabled=true \
  --set persistence.size=5Gi \
  --set resources.requests.memory=256Mi \
  --set resources.limits.memory=1Gi
```

### Multi-Target com Prometheus (Recomendado)

```yaml theme={"system"}
# values-prod.yaml
llm:
  provider: CLAUDEAI
secrets:
  existingSecret: chatcli-llm-keys
server:
  token: super-secret-token
tls:
  enabled: true
  existingSecret: chatcli-tls-certs
watcher:
  enabled: true
  interval: "15s"
  maxContextChars: 10000
  targets:
    - deployment: api-gateway
      namespace: production
      metricsPort: 9090
      metricsFilter: ["http_requests_*", "http_request_duration_*"]
    - deployment: auth-service
      namespace: production
      metricsPort: 9090
    - deployment: payment-service
      namespace: production
      metricsPort: 9090
      metricsFilter: ["payment_*", "stripe_*"]
    - deployment: worker
      namespace: batch
persistence:
  enabled: true
  size: 5Gi
resources:
  requests:
    memory: 256Mi
  limits:
    memory: 1Gi
```

```bash theme={"system"}
helm install chatcli oci://ghcr.io/diillson/charts/chatcli \
  --namespace chatcli --create-namespace \
  -f values-prod.yaml
```

> Quando targets estão em namespaces diferentes (ex: `production` e `batch`), o chart cria automaticamente um `ClusterRole` em vez de `Role` namespace-scoped.

***

## Próximos Passos

<CardGroup cols={3}>
  <Card title="Servidor" icon="server" href="/pt/features/server-mode">
    Configurar o servidor gRPC
  </Card>

  <Card title="Conexão Remota" icon="plug" href="/pt/features/remote-connect">
    Conectar ao servidor
  </Card>

  <Card title="K8s Watcher" icon="dharmachakra" href="/pt/features/k8s-watcher">
    Monitorar Kubernetes
  </Card>
</CardGroup>
