30 KiB

Hermes on Atlas: operator guide

This is the mental model and demonstration script for the operator instance at triage.bstein.dev. Read it once, then prove each section in the live UI. The consumer instance at chat.bstein.dev is intentionally separate and is not the place to perform infrastructure triage.

worker.bstein.dev is the owner-only engineering control plane. Its root serves the stock Hermes dashboard, including embedded chat/TUI and the native sessions, files, models, logs, Kanban, skills, plugins, MCP, profiles, and configuration surfaces. /terminal/ remains the raw full-screen TUI. The community WebUI is intentionally reserved for isolated consumer chat, where its conversation-first layout is a better fit.

Chat UX program (HUX) contracts

The twelve-card chat improvement program codes against the contracts in services/hermes/contracts/hux/ (schemas, examples, flags.json) and the rules in scripts/hux_policy.py. Read docs/hermes_hux_contracts.md before adding a route to the tenant router or a panel to the WebUI bridge; every feature is behind a HUX_FLAGS entry that defaults off.

Consumer chat and Telegram

chat.bstein.dev uses the pinned Hermes WebUI rather than the operator dashboard. Keycloak still authenticates every browser request, and the tenant router permanently assigns each Keycloak subject to one Hermes process and one PVC. The four slots are an isolation pool, not a provider round robin: every user starts with the same automatic provider/fallback policy and may change the model or reasoning effort for their own conversation. The WebUI and API reject reasoning levels above xhigh.

Telegram is optional. The Keycloak bootstrap creates kv/atlas/hermes/chat-telegram with a generated relay key and an empty bot_token. After creating the shared bot with BotFather, set only that field:

vault kv patch kv/atlas/hermes/chat-telegram bot_token='<telegram bot token>'

Restart or reconcile hermes-chat-router after changing the token. A user then signs in to the WebUI, selects Telegram, creates a ten-minute code, and sends the displayed /link command to the bot. The router accepts only direct chats, stores hashed Keycloak and Telegram identities, and forwards the message to that user's tenant API with the shared relay key. /unlink works from Telegram or the WebUI. Browser chat remains available when bot_token is empty.

The bot token and relay key must never be added to Git or a Kubernetes Secret. The router does not log prompt bodies, raw Telegram IDs, link codes, or tokens.

Switchyard capability routing

Switchyard chooses capability before reasoning effort. economy, balanced, advanced, and frontier select Luna-, Terra-, Sol-, and Astra-class work; low through xhigh control deliberation independently. Legacy AUTO keeps low/economy, medium/balanced, and high or xhigh/advanced behavior. Frontier is an explicit exceptional-work choice, not a synonym for xhigh.

Timeout, rate-limit, authentication, transport, and capacity failures retry an available provider at the same capability and effort. A failed test, rejected review, contradicted result, or incomplete evidence is a quality signal: keep the floor, change the failed plan, and raise capability or effort when needed. The concrete selected model, capability, effort, and rationale are recorded on durable worker receipts.

The hourly coordinator discovers the models visible to the Codex and Claude accounts, writes non-secret catalog and health evidence, and evaluates catalog candidates for capability fit before publishing Switchyard profiles. Claude discovery uses its Agent SDK initialize metadata, including the account-visible model list; it does not run a generation just to discover a model. A provider, catalog, or evaluation outage preserves the last known-good routes and records the refresh as deferred, so discovery does not silently become a routing bypass.

Existing pull-request continuation is available through coordinator-owned lineage: kanban_continue_pr.py validates the root task, recorded PR, branch, and current head before queuing a repair on that same PR. A signed continuation worker may update that exact owned ref through the SCM broker. Publication-only resume for a completed but unpublished SCM result is still being finalized; until its exact-run ownership, evidence preservation, and bounded finite-retry semantics are confirmed, keep the workspace commit and structured result recoverable and do not claim that path is live.

Private Jetson voice: multilingual TTS policy

hermes-tts on titan-21 bakes three checksum-pinned Piper voices and selects one per request from a fixed, allow-listed language field: en/ en-USen_US-amy-medium, ru/ru-RUru_RU-irina-medium, es/ es-MX/es-ESes_MX-claude-high (Piper's claude voice is Mexican Spanish; there is no Castilian es_ES-claude). Matching is case-insensitive and accepts both _ and - separators. Any language that is missing, unrecognized, or malformed falls back to English amy rather than erroring. The mapping is a fixed dict from language to one of the three baked model names only — a client-supplied voice field is never read, so no client input can select or construct a model path. All three voices are preloaded at process start (see dockerfiles/hermes-jetson-tts-server.py).

Hermes Chat deliberately exposes no TTS speaker/model choice. The deterministic WebUI image patch removes the pinned upstream voice selector, its label and translations, its browser/server preference persistence, and every outbound client voice field while preserving the TTS engine, speech rate/pitch, dictation, hands-free Voice Mode, and the conversation instrument. Legacy hermes-tts-voice browser state is deleted. Voice choice is therefore policy, not a client preference: validated English maps to amy, Russian to irina, Spanish to claude, and every unsupported or absent language falls back to amy.

The private WebUI voice bridge (dockerfiles/hermes-webui-atlas-voice.js, patched into api/routes.py by hermes-webui-atlas-patch.py) has no signal for the language of the assistant reply it is about to speak — it sends only text and engine. Until the WebUI or gateway attaches an explicit language field to that request, every reply speaks in the safe English default regardless of its actual language. Closing that gap needs a language signal upstream of the TTS call (e.g. tagging the assistant turn with a detected/declared reply language and threading it through hermes-webui-atlas-voice.jsapi/routes.py → the language field), not client- or server-side guessing bolted onto the TTS service itself.

The one-sentence explanation

Hermes is the persistent agent runtime and control surface; Codex or the local GPU model supplies reasoning, while Hermes supplies sessions, tools, skills, approval rules, identity, and the repeatable procedure that connects the model to Atlas evidence.

Hermes is not the model. Replacing gpt-5.6-terra with gpt-oss:20b changes the reasoning engine, but it does not replace the Hermes sessions, tools, skills, files, permission boundary, or workflow.

Request and evidence path

browser
  -> Keycloak login
  -> oauth2-proxy exact-user check
  -> operator Hermes pod and persistent workspace
  -> SOUL.md + AGENTS.md + selected skill
  -> Codex primary model
       -> read-only terminal/web/file tools
       -> Ariadne deterministic evidence
       -> retained Jenkins logs and artifacts
       -> Gitea commits and Flux state
       -> Kubernetes workloads, events, logs, and dependencies
       -> Pushgateway data queried through VictoriaMetrics
       -> Grafana query and alert context
  -> structured finding and proposed repo-side change
  -> human review and approval
  -> Git/Flux delivery outside Hermes

provider failure
  -> hermes-model-gate
       -> Hermes owns titan-24: Ollama serves gpt-oss:20b
       -> Wolf owns titan-24: gate returns 503; local inference yields

The operator agent pod runs on an ARM worker and does not reserve the GPU. Ollama is the component on titan-24 that owns GPU memory. The Lease hermes/titan-24-gpu-owner controls whether the model gate admits local inference. Normal operator conversations use independently authenticated Codex first, so Wolf ownership does not need to block the web agent.

Who does what

Component Responsibility What it does not prove
Hermes Maintains the conversation, chooses tools/skills, reasons over evidence, saves reports, and enforces the approval experience It is not the inference model and does not automatically have cluster-admin access
Ariadne Collects and normalizes deterministic cluster, Jenkins, and quality evidence into a timestamped bundle; may optionally run a local diagnosis Its diagnosis is not authoritative when stale, empty, or contradicted by the bundle
Jenkins Runs the suites and retains console/artifact evidence A final exit 1 alone does not identify the first failed gate
Pushgateway Receives suite/build quality telemetry A cumulative counter is not the current build result
VictoriaMetrics Stores and answers PromQL for quality and environment telemetry A Grafana color is not direct proof of root cause
Grafana Visualizes and alerts on VictoriaMetrics data A red panel must be traced to its query, labels, time range, and raw series
Flux Applies reviewed Git state to the cluster A recent reconciliation is correlation until the changed path matches the failure
Kubernetes Supplies workload, event, log, node, storage, and dependency evidence An unrelated unhealthy pod is not proof that CI failed because of the cluster

Direct Jenkins artifact requests currently require authorization and can return HTTP 403. That does not break the workflow: Ariadne retains selected Jenkins console tails and named artifact contents in its deterministic bundle. A report must say retained Ariadne evidence when that fallback is used; it must not pretend direct Jenkins access succeeded.

Publishing an agent image after review

The hermes-agent-image Jenkins job is the only supported agent image builder. It runs daemonless Kaniko v1.23.2 under the unbound hermes-image-builder ServiceAccount without a service-account token, host socket, privileged container, or writable Git credential. It accepts only an exact 40-character revision that is both the checked-out commit and current titan/atlas-iac main, so a human must merge the source PR first.

The build pod requires an ARM64 worker and gives hardware=rpi5 the maximum scheduler preference. Healthy rpi4 workers remain valid fallback capacity when the rpi5 pool cannot fit the full request. Cordoned, unhealthy, amd64, and reserved last-resort nodes remain excluded by the required placement boundary.

Kaniko runs as UID 0 because it must unpack an image root filesystem and enter that filesystem for Dockerfile RUN instructions. Its capability set is the minimum proven by an exact ARM64 no-push build of this Dockerfile: CHOWN, FOWNER, DAC_OVERRIDE, SETGID, and SETUID. SETGID is required because pinned Kaniko applies the base image's supplementary group list before each Dockerfile RUN; SETUID lets apt drop privileges to its _apt account while downloading package indexes. It still has no privilege escalation, service-account token, host path, daemon socket, or Docker/BuildKit TCP endpoint and uses the runtime-default seccomp profile. This is residual root-in-the-build-pod risk, bounded to disposable emptyDir storage and a human-reviewed main revision; Dockerfile changes require the same scrutiny as executable cluster code.

Pinned Kaniko v1.23.2 parses Dockerfile RUN heredocs but does not materialize their inline files when executing a command. The Jenkins lane therefore enables a bounded compatibility replay after copying the reviewed Dockerfile and runner from the same checked-out commit. Before every replay, the runner inventories the entire Dockerfile as logical instructions, including split opcodes, operators, and either Dockerfile escape character. It rejects every heredoc form outside the exact nine Node/Python blocks before launching an interpreter. Each accepted body is then replayed immediately after its corresponding Kaniko RUN, preserving source order before any dependent regression. Docker and BuildKit keep their native behavior because the compatibility argument defaults off. The final TypeScript build, Python compile, and source assertions remain mandatory, so an omitted or drifted replay fails before any image can pass release verification.

From worker.bstein.dev, trigger that one fixed job with:

jenkins_image_build_trigger.py '<reviewed full main commit>'

The helper has no general Jenkins credential or caller-selectable job name. Its Vault-projected token is bound by Jenkins only to hermes-agent-image. The job also requires its fixed publish confirmation. Each run claims the unique tag git-<reviewed-sha>-build-<jenkins-build-number> and refuses to overwrite an existing tag. It cross-checks Kaniko's digest and tagged-image evidence, then independently reads the pushed tag from Harbor before archiving a JSON record and Flux digest patch. A successful post-condition then revalidates the exact six-file evidence set and archives those six explicit paths with empty archives forbidden. Apply that patch on a new branch and submit it for human review; the build never changes Git, reconciles Flux, or deploys by itself. The helper posts only to the fixed HTTPS Build Token Root endpoint and accepts only its real queue responses: HTTP 201 or a non-followed HTTP 303 with an exact same-origin /queue/item/<number>/ location. An unauthenticated request is denied, and the token cannot select, configure, read, or administer another Jenkins job. The pipeline independently rejects any commit that is not the current origin/main, preserving the human merge/review boundary.

Harbor independently enforces an enabled immutable-tag rule scoped to only the bstein/hermes-agent repository and git-*-build-* tags. A second manifest PUT, retag, or deletion is rejected by Harbor even if a caller bypasses the Jenkins preflight. A revisioned, Flux-tracked policy Job creates or verifies that exact rule with a runtime-only Vault credential; it refuses to alter a conflicting rule and retries only explicit transport/readiness failures while Harbor starts. The same Job grants the existing Jenkins publisher only immutable-tag:list on bstein, preserving its other project scopes and never calling Harbor's separate secret-rotation endpoint. The pipeline uses that read-only permission to require the exact enabled rule before Kaniko starts. That check also makes an already-running Jenkins controller fail closed during rollout; Jenkins cannot become Ready on the new revision before the policy Job succeeds.

The tracked rollout order is deliberate: the revisioned Vault role Job must complete before the Vault Kustomization becomes Ready. A separate Flux Kustomization then runs the seed Job under the dedicated hermes-jenkins-token-seed identity, which can only create/read the exact kv/data/atlas/hermes/developer-jenkins path and request random bytes. Jenkins depends on both that seed and the Harbor policy Job; Hermes depends on Jenkins. The seeder uses KV-v2 CAS create-only semantics. It never changes an existing token, never fills a missing field in an existing secret, and fails closed when it cannot distinguish absence from a read error. The recurring Vault configuration job reconciles the same narrow role and policy.

Rotate this fixed-job token only as a coordinated operator action:

  1. Stop new hermes-agent-image triggers and wait for its queue and executor to drain.
  2. Read the current KV-v2 metadata version for kv/atlas/hermes/developer-jenkins.
  3. Generate a fresh value from Vault and patch only build_token with vault kv patch -cas=<current-version>. Keep the value in a mode-0600 temporary file or standard input, never a command argument or log.
  4. Roll Jenkins first and wait until it is Ready, then roll hermes-agent and wait until it is Ready. Do not resume triggers between those two consumers.
  5. Run one reviewed-main canary. If rollback is required, repeat the CAS patch with the previous value as another coordinated rotation; never delete the secret to make the seeder recreate it.

The actual supervised triage algorithm

  1. Classify the request as test/build triage, service health, or alert tuning.
  2. Read the latest Ariadne diagnosis and deterministic bundle with HTTP GET.
  3. Compare their timestamps. The deterministic bundle remains authoritative.
  4. Select a terminal failed build. Keep running or unknown builds out of the terminal-failure list.
  5. Identify the first enforced failed gate in this order: style -> loc -> coverage -> tests -> gate_glue -> sonarqube -> supply_chain.
  6. Cite the smallest decisive Jenkins log/artifact evidence. State whether it came directly from Jenkins or from Ariadne retention.
  7. Query the matching build/check/test series in VictoriaMetrics. Distinguish a current gauge from a cumulative counter and ignore zero-valued failure series.
  8. Correlate recent Gitea commits and the relevant Flux revision by timestamp and affected path. Recency alone is not causation.
  9. Check only the Kubernetes resources capable of explaining that failure. Classify observations as direct, contributing candidate, or background.
  10. Return Finding, Confidence, Evidence, Likely cause, Blast radius, Next checks, Repo-side fix, and Approval required.
  11. Stop at a proposal. A human reviews the patch or action; Git and Flux remain the delivery path.

What Hermes can read and what it cannot do

The live hermes-triage ServiceAccount can get/list/watch ordinary workload, log, event, ingress, storage, Flux, and image-automation metadata. It cannot read Kubernetes Secret values, create exec sessions, patch Deployments, or patch Flux Kustomizations. The configured command deny list also blocks common Kubernetes and Flux mutations.

The security boundary is layered:

  1. Keycloak authenticates the person.
  2. oauth2-proxy restricts the operator surface to Brad.
  3. The operator has a separate namespace, PVC, configuration, and ServiceAccount.
  4. Kubernetes RBAC is the hard API authorization boundary.
  5. NetworkPolicy limits reachable paths where configured.
  6. Hermes approvals and instructions provide a user-facing safety layer.

A skill is procedure and context, not a permission grant. Adding a sentence to a skill cannot bypass Kubernetes RBAC.

What “Hermes learns the workflow” means

It does not silently retrain model weights on cluster data. Learning here means that a successful repeated procedure is written as a reusable skill on the operator PVC or versioned in Git. The skill describes when it should trigger, the evidence order, interpretation rules, output contract, and safety boundary.

The current workflow has a versioned top-level skill and persisted specialist skills for:

  • orchestration and evidence reporting;
  • retained Jenkins evidence;
  • quality metrics;
  • Gitea/Flux correlation;
  • Kubernetes failure classification;
  • Grafana metric provenance;
  • Soteria backup health;
  • approval-required actions.

The model still evaluates fresh variable evidence on every incident. The skill makes the process repeatable; it does not freeze the answer.

The four operator skills to remember

  • triage-titan-test-failures: CI, tests, builds, quality gates, and suspected test-environment regressions.
  • triage-atlas-service-health: active service or cluster incidents and red high-level health panels.
  • tune-atlas-alerts: noisy alerts, impossible metrics, bad PromQL, and generator-owned Grafana corrections.
  • master-hermes-on-atlas: hands-on training, assessments, architecture, and claim audits.

Do not start by choosing raw tools. State the operational question and let the skill route to the narrow evidence source.

Two live, repeatable proof cases

Proof 6: Soteria build 272

  • Terminal result: failure.
  • Tests: 318 passed, zero failed.
  • Local coverage: 96.195 percent.
  • First enforced failure: SonarQube new_coverage=0.0 against threshold 80.
  • Runtime: Soteria remained Ready.
  • Correct conclusion: a Sonar new-code policy/reporting problem, not a test or Kubernetes capacity failure.
  • Correct restraint: do not weaken the policy until scanner import and baseline evidence identifies whether the issue is configuration or legitimate new uncovered code.

Proof 7: Ananke build 242

  • Terminal result: failure.
  • Local coverage gate: 61.8 percent and failed.
  • Other checks: tests, SonarQube, supply-chain, LOC, docs naming, and gate glue were healthy.
  • Sonar new-code coverage: 93.1 percent, which is a different scope.
  • Correct conclusion: local coverage input/scope caused the enforced failure; do not call the Sonar number contradictory without comparing inputs.
  • Correct restraint: do not lower the threshold until the retained local gate inputs are readable.

The full sessions and redacted Markdown exports are in Sessions and Files/triage-proof.

Five-minute demonstration

  1. Open Models and show openai-codex/gpt-5.6-terra as primary and gpt-oss:20b as local fallback.
  2. Open Skills and show the four operator skills plus the persisted component skills.
  3. Open Proof 6 - Soteria 272 Sonar new coverage triage in Sessions.
  4. Point out the timestamped bundle, exact build/artifact evidence, metric corroboration, healthy runtime, fact/inference separation, and approval boundary.
  5. Open Proof 7 and explain why local coverage and Sonar new-code coverage can differ without either number being fabricated.
  6. End by showing that Hermes proposes a repo-side correction but cannot patch the Deployment or Flux Kustomization with its ServiceAccount.

Use this short explanation:

Hermes is the persistent, permissioned workflow layer around the model. In this cluster Ariadne collects deterministic evidence, Hermes correlates it with retained Jenkins artifacts, Git/Flux state, Kubernetes health, and quality metrics, and then returns a supervised proposal. Repeated procedures become explicit skills. Kubernetes RBAC prevents the agent from turning a diagnosis into an unreviewed infrastructure change.

Prompts that exercise the real system

  • Use $triage-titan-test-failures. Triage the worst current terminal CI failure and link every decisive piece of evidence.
  • Use $triage-titan-test-failures. Triage Ananke build 242. Separate local coverage from Sonar new-code coverage.
  • Use $triage-atlas-service-health. Explain the VictoriaMetrics outage from current state and retained events; separate recovered impact from current impact.
  • Use $tune-atlas-alerts. Trace one currently firing alert to its generated source and raw PromQL, but do not edit it.
  • Use $master-hermes-on-atlas. Assess me on the request path and permission boundary. One question at a time.

Private voice: choosing the Piper voice from the STT-detected language

Hands-free voice mode in chat.hermes.bstein.dev selects the private Piper voice from the language the private Jetson Whisper service reports for the user's own speech. The signal travels one way only, and every hop narrows it:

  1. hermes-stt returns {text, model, language}. language is whatever Whisper decoded with, accepted only as a bare ISO-639 token (en, ru, es, yue, …); anything else is reported as empty.
  2. hermes_stt_client.py writes the usual <stem>.txt transcript plus a <stem>.language sidecar. The transcript stays the only .txt in the output directory, so the stock Hermes local-command contract is unchanged.
  3. The patched local-command STT envelope reads that sidecar and adds language to its result; /api/transcribe re-validates it and returns it next to transcript.
  4. atlas-voice.js keeps that value only for the turn it belongs to. It is bound to the voice-mode generation token and the chat session id, consumed exactly once by the reply that turn produced, and cleared on cancellation, restart, session change, an empty transcript, or a transcription error.
  5. /api/tts accepts language only from the fixed allow-list and otherwise sends English. The Jetson TTS service applies the same allow-list again as the final authority.

What this does not claim. The language is the language the user spoke, not the language of the reply. A model asked a Russian question may answer in English and will then be read aloud by the Russian voice, and vice versa; this is a deliberate policy choice for hands-free mode, not a detection failure. Nothing here detects the language of assistant text.

Everything else stays English. Typed messages, the manual read-aloud button, and any assistant reply that was not produced by a hands-free spoken turn carry no trusted STT signal, so they synthesize with en_US-amy-medium. A voice field from a browser is never honoured at any hop.

Honest limits

  • Hermes does not currently apply production or cluster changes autonomously.
  • Direct Jenkins console/artifact access may be forbidden; Ariadne retention is the current fallback and must be named as provenance.
  • Local gpt-oss:20b is useful for bounded work but is slower and less reliable for multi-source triage than Codex.
  • The current Ariadne local diagnosis can return an empty model response. That does not invalidate the deterministic bundle or prevent Codex-backed Hermes from triaging it.
  • A single successful case demonstrates capability, not mastery. Mastery means leading different real incidents, improving the skill after failures, and teaching the architecture without prompts.

Distributed execution-pool rollout boundary

  • Do not reconcile the pool until the approved credential owner has provisioned six distinct Vault fields: execution_worker_{0,1,2}_claude_credentials_json and execution_worker_{0,1,2}_codex_auth_json. Each ordinal needs an independent account or refresh-token lineage; copying one rotating refresh token into multiple fields recreates the lost-update failure this design prevents.
  • Worker credential files live on separate ordinal-owned RWO provider-access claims. Provider refresh updates these durable private copies across Pod restarts; they are never synchronized back to Vault. Rotate one bootstrap credential at a time through the reviewed Vault workflow and reinitialize only that ordinal after human approval.
  • Existing task worktrees remain on the single local owner lane. Only tasks without workspace_path enter the distributed pool, where each ordinal owns one RWO checkout. Repository and base-branch identity comes from the canonical board registry rather than task-supplied metadata.
  • Model Pods have no pool key, broker mount, broker egress, or Kubernetes token. Ordinal mediator Deployments are separate network identities that co-mount the matching workspace PVC; they alone authenticate exact-run results and reach the PR14 SCM broker.
  • The ordinal workspace claim is ReadWriteMany because the worker and its mediator both mount it. With ReadWriteOnce a drain or preemption that moved only one of them left the other holding the attachment on the old node, and the ordinal deadlocked on Multi-Attach until an operator deleted a Pod. Colocation is now a scheduling preference and both Pods run at scavenger priority, so either can be evicted and rescheduled on its own. There is deliberately no PodDisruptionBudget: this is a best-effort pool and a budget would impede node drains. Claims only one Pod mounts stay ReadWriteOnce.
  • lease_failed is a retryable durable state, not a terminal one. It means the ordinal was released but Kanban has not confirmed the outcome, so every maintenance pass retries it. Only finalized and stale are terminal, and only terminal rows are garbage-collected, so no run is dropped before the pool knows what happened to it. If the log keeps reporting a deferred lease park for the same run, Kanban is refusing an exact-run park on a task it still reports as running: inspect that task rather than deleting the row.
  • Ordinary work publishes a newly created broker branch. A trusted coordinator-issued continuation is the sole exception: it private-clones the latest verified head of the recorded PR branch and receives a signed grant to update that exact ref. It never adopts a caller-provided ref, force-pushes, or creates a replacement PR. A submission that cannot land blocks the run with the reason and leaves the commits on the ordinal's workspace, so prior work is recoverable.
  • Provider CLIs install once per pinned version onto a durable per-ordinal tools claim, re-verified against the real binaries so a pruned cache reinstalls. The pool is intentionally absent from the hermes Kustomization's healthChecks: gating that 10m window on a best-effort pool would stall hermes-chat and hermes-observer-bindings, which dependsOn: hermes.
  • A hashed execution-pool ConfigMap, protocol-version readiness checks, and versioned SCM boundary name make code/config changes controlled rollouts. Verify the config revision, protocol readiness, and worker/mediator health after Flux applies a reviewed rollout.

Your shortest path to fluency

  1. Explain the request diagram without looking.
  2. Explain why Ariadne and Hermes are separate components.
  3. Reproduce Proof 6 from the raw bundle and metrics.
  4. Reproduce Proof 7 and explain the two coverage scopes.
  5. Produce the live RBAC allow/deny matrix with kubectl auth can-i.
  6. Create one small writable skill from a repeated sub-workflow, test a trigger and non-trigger case, then improve it.
  7. Lead one new incident while Hermes coaches rather than answers for you.
  8. Teach the five-minute demonstration to another person.

At that point the interview claims are demonstrable. Continue repeating real incidents before describing yourself as fully autonomous or the system as self-correcting.