Repository navigation
K8s fleet roster/observe UI — console can't drill into an existing k8s fleet #146
Description
Problem
Clicking a k8s-runtime fleet in the Fleets panel doesn't drill into its member roster. selectFleet (console/src/main.ts:448-463) explicitly declines and shows an info toast — this is a known, intentional stopgap (see PR #145's description), not a regression. Before #145 (2026-09-06) k8s fleets weren't even visible in the Fleets list, so this is newly reachable but was never wired.
Root cause (confirmed by reading current main, 2026-09-07)
The entire roster/observe read path is ECS-only, several layers deep:
oab-mcp'starget()(crates/oab-mcp/src/lib.rs:449-459) hard-errors for a k8s-runtime fleet: "fleet {name} is a k8s-runtime fleet; this tool only supports ecs fleets".t_runtime_context(crates/oab-mcp/src/lib.rs:850) unconditionally callsscp::observe_identity(&aws)(AWS/STS) — never branches to the already-existingobserve_k8s_identity(crates/studio-cp/src/lib.rs:281, built in Phase 1 / studio#63 slice 3e) even thoughRuntimeContext's shape is already unified across both drivers.- There is no k8s-side roster tool at all —
deploy_list/t_listhas no equivalent of "list Deployments in this namespace, mapped to the console'sDeploymentshape" the way ECS'sroster_over_mcp(src-tauri/src/lib.rs:261) does. console/src/main.ts'stick(), andsource.ts'slistDeployments/runtimeContext, are cluster-keyed throughout — no context/namespace equivalent path exists on the console side either.
ProvisionDriver (crates/oabctl/src/driver.rs) only has apply/scale/delete — no list/observe method on the trait, so there's no existing seam to hang a k8s roster read off of.
Scope (rough slices, same shape as studio#63/#104's phased delivery)
- studio-cp: a k8s roster read — list Deployments in a
(context, namespace), scoped to a fleet'smembers(mirroringcrates/oabctl/src/k8s_driver.rs's existingkubeclient setup), mapped to a shape the console can render alongside ECS'sDeploymenttype (replicas/ready vs ECS's desired/running count, image, etc.). - oab-mcp: fix
t_runtime_contextto dispatch onbinding.runtime(observe_k8s_identityfor k8s, existing path for ecs); add the new roster tool from (1); relaxtarget()'s hard error only for the calls that now support both runtimes (identity/roster), not for the ones that genuinely stay ecs-only (apply/scale/delete stay behind the existing k8s dispatch added in studio#104/feat(studio-cp,oabctl): k8s deploy_provision dispatch (studio#104, resumed after #111) #114 instead, not this trait). - src-tauri: extend
deploy_list/runtime_contextbridge commands (or add k8s-specific ones) to pass context+namespace instead of cluster when the target fleet is k8s. New bridge commands need the usual "no local signal,bundle-macosCI only" caveat ([[studio-tauri-bridge-layer-gotcha]]). - console:
main.ts'sselectFleet/tickbranch onfleet.runtimeinstead of declining;source.tsinterface +Deployment/RuntimeContexttypes grow the k8s-shaped fields; fixtures/tests updated.
Not in scope
Scaling/starting/stopping k8s deployments from the console — that's a separate action surface (ProvisionDriver::scale/delete already exist for k8s via studio#104/#114's provider dispatch on the create path; wiring the existing-fleet scale/delete buttons to it is a follow-on, not blocking the read-only roster view this issue is about).
🤖 Filed by Orca
Activity
brettchien commentedon Sep 7, 2026
More detail (2026-09-07, after reading
agent-lifecycle/k8s_driver.rsmore closely)Good news: the design work for this is already done, only the code is missing. Corrects/sharpens the slice-1 scope from the issue body.
The canonical 6-state model already has a k8s row.
docs/adr/agent-lifecycle.md§6's projection table (line ~140) maps k8s Pod signals onto the sameDiscriminatoraxes ECS uses:deletionTimestamp != null⟺ ECSdesiredStatus STOPPED(Stopping), Pod phase + readinessProbe ⟺ Starting/Running,Unknown(node lost) → Unhealthy(fenced), etc. This was drafted alongside ECS's row, not an afterthought.Only the ECS side got implemented.
crates/agent-lifecycle/src/ecs.rsimplementsRuntimeDriverfor ECS (EcsDriver::project(&EcsTask, verified_before) -> Discriminator, ~230 lines incl. tests) — there is nok8s.rssibling.crates/oabctl/src/k8s_driver.rs's own module doc says this explicitly (written during studio#63 slice 3b, i.e. this was known and deliberately deferred, not missed): "Observing k8s state into the canonical 6-state ... is also out of scope here — it's substantial enough on its own ... to land as its own follow-up." This issue is that follow-up.The console side needs less than slice-4 originally said.
console/src/types.ts'sDeployment(desired/current/ready+instances: InstancePhase[], eachInstancePhase.state: AgentState) is already runtime-agnostic — it's expressed in the canonical 6-state, not ECS-specific fields. So a k8s roster tool that fills the same JSON shape needs no console type changes for the roster data itself. What still needs console changes is purely the read-path plumbing:main.ts'sselectFleet/tickpass an ECSclusterstring today; they need to pass k8scontext/namespaceinstead whenfleet.runtime === "k8s".Revised slice 1 (studio-cp / agent-lifecycle): add
crates/agent-lifecycle/src/k8s.rs— aK8sPodnative-observation struct (phase, conditions/readiness,deletionTimestamp, a CP/director cordon signal foraccepting_work) +K8sDriver::project()implementingRuntimeDriver, mirroringecs.rs's shape and directly off the ADR table (no new design decisions needed, a fairly mechanical port). Then akube::Api<Pod>(or Deployment+Pod) list scoped to(context, namespace)+ fleetmembers, feeding each observation throughproject(), shaped into the existingDeployment/InstancePhaseJSON.Slices 2–4 (oab-mcp dispatch fix + new roster tool, src-tauri bridge, console read-path branch) are unchanged from the issue body.