App runs & CLI bridge

How app.kprompt.ai/run works: device login, Connect CLI, kprompt run listen, why jobs stay queued, approve modes, and troubleshooting. No cluster credentials in the control plane.

Team /run lets you compose a prompt in the browser. Execution always happens on an enrolled laptop with local kubeconfig — never inside api.kprompt.ai. If nobody is running kprompt run listen, the job stays queued forever. That is intentional (ADR-0021), not a hang.

Flow at a glance

Browser compose → queue → local bridge → PlanResult

You (browser)     app.kprompt.ai/run     →  POST /v1/runs  (status: queued)
Laptop bridge     kprompt run listen     →  POST /v1/runs/claim
                  local plan pipeline    →  kubeconfig stays on the laptop
                  POST /v1/runs/{id}/result  →  app shows plan / awaiting_approve
  • Control plane stores prompt + status + PlanResult summary — never kubeconfig or cluster tokens
  • Same local safety + cached org policy as normal CLI plans
  • Mutations never auto-apply from the plane; plan_only never applies; require_approve waits for Approve in the app

1. Enroll the CLI (device login)

On the laptop that can reach the cluster:

kprompt login            # prints a user code + Connect URL
kprompt login --open     # also opens the browser
kprompt whoami           # confirm org + member
  • CLI shows a short user code (for example WXYZ-ABCD) and a URL under app.kprompt.ai/connect
  • Sign in to the Team app in the browser if needed
  • Open Connect CLI, enter or confirm the user code, Approve
  • CLI receives a kp_… token → ~/.kprompt/credentials.yaml (mode 0600)

If whoami or doctor shows Team enrollment Forbidden, run kprompt logout then kprompt login again. See Team enrollment for policy and audit details.

2. Start the bridge worker

Leave this running in a terminal while you use /run in the app:

kprompt run listen
# optional:
# kprompt run listen --interval 3s --worker-label laptop-muhtalip

The worker polls POST /v1/runs/claim, runs the same plan pipeline as the CLI (never auto-applies), and posts the result. One active claim per worker; kubeconfig and LLM keys stay local.

3. Compose and queue in the app

  • Open app.kprompt.ai/run
  • Enter the prompt (for example deploy redis), optional namespace and context hint
  • Pick approve_mode: plan_only (never apply), require_approve (pause for Approve/Deny), or auto_if_policy_allows (still subject to hard denies)
  • Queue run — status starts as queued

The /run page itself says: Jobs stay queued until claimed. The empty-state copy points at kprompt login && kprompt run listen (also linked from Connect CLI).

Why status stays queued

queued means the job is waiting for a bridge. The app does not browse or mutate the live cluster from the browser. Common causes:

SymptomLikely causeFix
Stuck on queuedNo kprompt run listen on an enrolled laptopStart the bridge; keep the terminal open
listen errors / claim failsStale or missing kp_… tokenkprompt logout && kprompt login && kprompt whoami
Wrong cluster / contextcontext_hint does not match a local kubeconfig context or aliasFix hint, or kprompt config alias set …; check kubectl config get-contexts
Doctor: Team enrollment FAILAPI Forbidden or expired device sessionRe-login; confirm org membership in the app

Approve modes

ModeBridge behavior
plan_onlyPlans and posts PlanResult; never applies (including Replay / drill)
require_approveMutating plans pause at awaiting_approve until Approve in the app; then the bridge may apply
auto_if_policy_allowsMay apply only when org policy allows; hard denies and wipe-class still block

Replay / drill

From a run or audit detail, Queue drill run re-queues the same prompt as plan_only with a staging-ish context hint. Prod-like hints are blocked. Still needs a live run listen worker — drill is not an in-browser executor.

Gotcha: drill often sets context_hint to staging. If that name is not a local kubeconfig context or alias, the bridge fails after claim. Map it with kprompt config alias set staging kind-kprompt-demo, or queue a fresh run with an empty / real context hint.

Why status is failed (after claim)

queued → running → failed means the laptop claimed the job but the local plan pipeline errored before a PlanResult existed. Check the red error field on the run detail page (authoritative), the bridge terminal (Posted run_… → failed: … on recent builds), and kprompt doctor on the same machine as run listen.

Error (typical)CauseFix
missing API key / providerNo BYOK key for the configured providerexport KPROMPT_GEMINI_API_KEY=… (or use Ollama) · or kprompt secrets pull
kube context "staging" not foundDrill / compose hint ≠ local contextsEmpty hint, real context name, or config alias set
429 / quota exceededGemini (or other) free-tier limitWait for reset, switch model, or use Ollama — see Providers
Org policy max_risk … exceedsPlan risk above cached org ceilingSoften org max_risk, or use a read-only / lower-risk prompt
unknown intentPrompt outside supported ops (e.g. create a cluster)Rephrase to a supported intent — see Commands

Providers details for Gemini free tier: Providers. Capability map: Commands.

Local sanity check (same kube + provider as the bridge)

kprompt doctor
kprompt --context kind-kprompt-demo "list pods" -n default
# then re-queue in the app and keep: kprompt run listen

What this is not

  • Not a hosted cluster browser (Lens-style live inventory in the plane)
  • Not the in-cluster Observe agent (Helm kprompt-agent) — that watches namespaces; this worker is laptop-side Team jobs
  • Not silent Autopilot apply — mutations stay gated

Related: Team enrollment · Safety · Observe agent.