Safety
How kprompt gates cluster mutations: prompt-level hard denies, plan risk levels, explicit approval, and tighten-only org policy.
Safety features reduce risk; they do not make kprompt safe for unattended production use. The product is experimental. Always review the plan. Skip --approve until you understand the proposed actions.
Every mutating plan is risk-evaluated before apply. On a TTY, kprompt asks y/N unless you pass --approve. Read-only intents (get, list, explain, investigate, why, timeline, impact, audit, cleanup, search, score, architecture, learn, drift, logs, describe, performance, trace, dashboard, optimize, graph, Istio traffic, GitOps status) do not require approval.
Where the checks run
The pipeline is prompt → intent → plan → safety → approval → executor → Kubernetes. Safety runs at two distinct points, which is why some prompts never reach the model at all.
| Stage | What it checks | Effect |
|---|---|---|
| Prompt check | Destructive natural-language patterns | Denied before any LLM call — no token spend |
| Plan evaluation | Actions, resource kinds, names, integration rules | Assigns risk or denies the plan outright |
| Org policy overlay | Cached Team policy, when enrolled | May only tighten the local verdict |
| Approval | TTY confirmation or explicit --approve | Last gate before the executor runs |
Hard denies
Some prompts are refused by pattern before the model is called: wiping or destroying the cluster, deleting everything or all namespaces, and deleting a namespace by name. These are cheap, deterministic refusals rather than a judgement call left to the LLM.
Refused before any LLM spend
$ kprompt "delete everything in the cluster"
🚨 Intent: destructive cluster operation
🛡️ Safe execution: denied
😅 Your cluster lives another day
Next: kprompt "delete deployment <name>" -n <namespace>Wipe-class denials rotate a small flavor pack of punchlines (stable per prompt) and always append a Next remediation line with a named-target example. The punchline is branding; the Next line is the teachable path.
| Plan-level rule | Why |
|---|---|
| Delete must target Pod, Deployment, or Service | Any other kind is refused rather than guessed at |
| Delete must name one resource | Names like *, all, everything, or --all are refused as unscoped |
| Delete without a resource kind is refused | An ambiguous target is never resolved for you |
| Namespace deletion is always refused | Blast radius is too large for a compiled plan |
Example plan-level deny
kprompt "delete all pods in production"
# Risk: denied — name a single resourceRisk levels
Plans surface one of four verdicts. Denied plans never apply. Medium and high plans still need explicit approval — risk is information for your review, not permission to skip it.
| Risk | Typical intents | Approval |
|---|---|---|
| low | Reads, explain, investigate, learn, drift, optimize reports, service graphs, GitOps status | None required |
| medium | Scale, deploy, install, upgrade, rollback, patch, workflows, Tekton, KEDA, GitOps sync | TTY y/N or --approve |
| high | Named deletes, Crossplane cloud claims, unrecognised intents | Explicit approval; Crossplane needs strong approval |
| denied | Hard-deny prompts and unsafe plans | Never applies |
learn and drift are RiskLow (read-only scans). Optional approve-gated GitOps sync follow-ups from drift are separate KindGitOps plans at medium risk. If an older CLI treated drift as high, upgrade — org max_risk=medium would incorrectly deny those scans.
Integration-specific rules layer on top for Helm, Argo Workflows, Tekton, KEDA, Istio, Crossplane, and GitOps, so a risky chart install or a cloud claim is not treated as a generic mutation. Multi-tool mutating routes produce one aggregate plan and a single approval rather than a chain of prompts.
Diffs and blast radius
When a live object already exists, plans include a before→after diff so you review the actual change rather than only the intent summary. That is the difference between approving "scale api to 10" as a sentence and approving it as a concrete replica change on a named Deployment.
Multiple clusters
Fan-out is deliberately asymmetric: reads and optimize rollups can span contexts freely, while mutations cannot be approved for many clusters by accident. --approve never implies cross-context apply; you confirm each context or pass --approve-each-context explicitly. Setting require_alias_match true refuses a mutation unless your kubectl current-context matches the alias you targeted.
Org policy (when enrolled)
A cached Team policy can only tighten local rules — it never loosens a local hard deny. Pull it with kprompt policy pull and inspect it with kprompt policy.
| Policy field | Effect |
|---|---|
| max_risk | Denies any plan whose risk exceeds low, medium, or high |
| deny_intents | Denies named intents outright |
| allow_namespaces | Restricts plans to an allowlist of namespaces |
| deny_namespaces | Denies plans targeting listed namespaces |
| require_approve | Forces approval for medium risk and above |
Example org deny (max_risk=medium vs a high plan)
kprompt policy
# max_risk: medium
kprompt "delete deployment redis" -n payments
# 🛡️ Org policy max_risk is medium — plan risk high exceeds itWhen enrolled, each plan also best-effort pushes a planned, denied, or applied audit event to the control plane. Disable it with KPROMPT_DISABLE_AUDIT=1.
What safety does not do
- It does not verify that a plan is correct — only that it is not obviously destructive
- It does not replace kubeconfig RBAC; kprompt can only do what your credentials allow
- It does not redact Secret values from reads you are already authorised to perform
- It does not make --approve in CI equivalent to human review
- It does not cover generic mutation of arbitrary resource kinds, which stays out of scope
Treat the safety engine as a floor, not a ceiling. The honest limits, including what Autopilot will and will not do, are documented on the roadmap.