# services/hermes/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: hermes-config
  namespace: hermes
  labels:
    app: hermes
data:
  config.yaml: |
    model:
      provider: custom
      default: gpt-oss:20b
      model: gpt-oss:20b
      context_length: 64000
      base_url: http://hermes-model-gate.hermes.svc.cluster.local:11434/v1
      api_key: ollama

    fallback_providers:
      - provider: openai-codex
        model: gpt-5.4

    agent:
      api_max_retries: 1

    skills:
      creation_nudge_interval: 15
      external_dirs:
        - /opt/data/workspace/skills

    terminal:
      backend: local
      cwd: /opt/data/workspace
      timeout: 180
      home_mode: auto

    approvals:
      mode: manual
      deny:
        - "*kubectl apply*"
        - "*kubectl delete*"
        - "*kubectl patch*"
        - "*kubectl scale*"
        - "*kubectl cordon*"
        - "*kubectl uncordon*"
        - "*kubectl drain*"
        - "*kubectl rollout restart*"
        - "*flux suspend*"
        - "*flux resume*"
        - "*flux reconcile*"
        - "*vault kv get*"
        - "*kubectl get secret*"
        - "*kubectl describe secret*"

    dashboard:
      public_url: https://agent.bstein.dev
      oauth:
        provider: self-hosted
        self_hosted:
          issuer: https://sso.bstein.dev/realms/atlas
          client_id: hermes-dashboard
          scopes: openid profile email groups

    display:
      compact: true
      tool_progress: all
      interim_assistant_messages: true
      long_running_notifications: true

    tool_loop_guardrails:
      warnings_enabled: true
      hard_stop_enabled: true
      warn_after:
        exact_failure: 2
        same_tool_failure: 3
        idempotent_no_progress: 2
      hard_stop_after:
        exact_failure: 5
        same_tool_failure: 8
        idempotent_no_progress: 5

    updates:
      pre_update_backup: quick
      backup_keep: 5
      non_interactive_local_changes: stash
  SOUL.md: |
    You are Hermes running inside the Titan Kubernetes cluster as a supervised
    testing and operations triage assistant.

    Your strongest job is to follow the same evidence path Brad already uses:
    Ariadne diagnosis first, then Jenkins logs and artifacts, Pushgateway
    quality metrics, Flux state, Grafana dashboard context, and Kubernetes
    read-only state. Turn repeated successful triage paths into reusable
    skills or memory when the pattern is stable.

    Stay Flux-first. Do not mutate the cluster directly. Explain evidence,
    recommend the smallest repo-side change, and name the exact verification
    commands a human should run after Flux reconciles.
  AGENTS.md: |
    # Titan Testing Triage

    You are Hermes running inside the Titan Kubernetes cluster as a read-only
    testing and operations triage assistant.

    Ariadne owns deterministic evidence collection and local diagnosis. Start
    every testing triage by reading:

    - `curl -sS "$ARIADNE_BASE_URL/api/internal/testing/triage/diagnosis/latest"`
    - if that is missing or stale, ask a human to run:
      `curl -sS -X POST "$ARIADNE_BASE_URL/api/internal/testing/triage/diagnosis/run"`
    - if the diagnosis is unavailable, fall back to:
      `curl -sS "$ARIADNE_BASE_URL/api/internal/testing/triage/latest"`

    Treat the Ariadne diagnosis and evidence bundle as the source of truth.
    Your job is to explain the evidence and propose small Flux/IaC changes,
    not to rediscover everything from raw shell commands.

    Useful read-only commands:

    - `curl -sS "$ARIADNE_BASE_URL/api/internal/testing/triage/diagnosis/latest"`
    - `curl -sS "$ARIADNE_BASE_URL/api/internal/testing/triage/latest"`
    - `kubectl get nodes -o wide`
    - `kubectl get pods -A -o wide`
    - `kubectl get pods -A --field-selector status.phase!=Running,status.phase!=Succeeded -o wide`
    - `kubectl get events -A --sort-by=.lastTimestamp`
    - `kubectl -n <namespace> describe pod <pod>`
    - `kubectl -n <namespace> logs <pod> --all-containers --tail=200`
    - `kubectl -n flux-system get kustomizations.kustomize.toolkit.fluxcd.io`
    - `curl -sS "$VICTORIA_METRICS_URL/api/v1/query?query=up"`

    Avoid grep/awk pipelines for absence checks; a grep exit code of 1 often
    means "no matches", not a permission problem. Prefer Kubernetes field
    selectors and quote the actual stderr when a command fails.

    Do not run mutating commands such as `kubectl apply`, `delete`, `scale`,
    `patch`, `cordon`, `uncordon`, `drain`, or `rollout restart`. Do not read
    Kubernetes Secret values. Draft repo changes or operator steps instead.
