Help an application developer ship and operate a service on OpenChoreo through the control-plane MCP server. Discover the live platform shape via MCP; read detailed references only when the task needs them.
Step 0 — Confirm MCP connectivity
Run list_namespaces. If the tool isn't reachable, tell the user the openchoreo-cp MCP server needs configuring per https://openchoreo.dev/docs/ai/mcp-servers/ and stop.
Step 1 — Load concepts (MANDATORY)
Read ./references/concepts.md in full before anything else. Not optional, even if the task looks simple — you'll get these wrong from memory. Load once per session; if you catch yourself acting without it, stop and load now.
Then load the matching reference for the task:
- First-time deploy (no Project yet, or first time touching OpenChoreo) →
./references/getting-started.md - Working with existing Components → straight to the matching recipe. To pick between BYO and source-build for an existing Component,
get_componentand checkspec.workflow: present →build-from-source.md, absent →deploy-prebuilt-image.md.
Step 2 — Load the PE skill for platform tasks
If the request touches ProjectType / ComponentType / ResourceType / Trait / Workflow (or cluster variants) or anything under What this skill cannot do, also load ../openchoreo-platform-engineer/SKILL.md. If the PE skill isn't installed, escalate.
What this skill can do
- Projects — create, update.
create_projecttakes an optionaltype_name/type_kind/parametersreferencing a PE-authored(Cluster)ProjectType; omitted, it defaults to thedefaultProjectType. A project's cell must be deployed per environment before its components can be → see Deploy the project cell indeploy-and-promote.md. - Components — create, update,
patch_componentforauto_deploy/parameters/traits/workflow/ metadata.- BYO image →
deploy-prebuilt-image.md - Source-build →
build-from-source.md
- BYO image →
- Workloads — image, ports, endpoints, env vars, files →
configure-workload.md - Attach Traits — pick from the platform's catalog →
configure-workload.md - Connect components — endpoint dependencies; platform injects env vars →
connect-components.md - Consume Resources — managed-infrastructure dependencies (databases, queues, caches); platform injects outputs as env vars and file mounts via
dependencies.resources[]→use-a-resource.md - SecretReferences — CRUD +
secretKeyRefconsumption →manage-secrets.md. TheClusterSecretStoreis PE-owned. - Deploy and promote — deploy the project cell per env (
create_project_release_binding, pin seeded by the controller), then bind aComponentReleaseto an Environment and promote both along the DeploymentPipeline →deploy-and-promote.md - Per-environment overrides — replicas, resources, env vars, trait config on the ReleaseBinding →
override-per-environment.md - Soft-undeploy / rollback —
update_release_binding release_state: Undeploy, or rebind to a priorComponentRelease. - Hard-delete developer resources —
delete_component,delete_workload,delete_release_binding,delete_project,delete_component_release. Destructive; confirm first. Nodelete_namespace— PE-side. - Inspect runtime — Component / ReleaseBinding
status.conditions[]andstatus.endpoints[];get_resource_treeto map a binding to its rendered K8s resources;get_resource_events/get_resource_logsfor pod-level evidence; WorkflowRun logs and events →inspect-and-debug.md - Discover platform resources (read-only) — ProjectTypes, ComponentTypes, ResourceTypes, Traits, Workflows, Environments, DeploymentPipelines, planes.
What this skill cannot do
Platform-side work: authoring ProjectTypes / ComponentTypes / ResourceTypes / Traits / Workflows, Environments, DeploymentPipelines, planes, authorization, gateway / secret-store / IdP config, observability setup, longer-horizon log / metric / trace queries (pod-level events and current logs are covered via get_resource_events / get_resource_logs).
Load ../openchoreo-platform-engineer/SKILL.md if it's installed; otherwise tell the user to escalate to a platform engineer. PE scope catalog: https://openchoreo.dev/docs/platform-engineer-guide/.
Tool surface
One MCP server: openchoreo-cp. Throughout this skill, tools are referenced by bare name (e.g. get_component); your agent wraps with its prefix (Claude Code uses mcp__openchoreo-cp__<tool>).
ComponentType / ResourceType / Trait / Workflow and the plane tools are scope-collapsed: one tool with a scope arg — "namespace" (default) or "cluster" for the platform-wide Cluster* resource. This skill always uses the canonical name + scope. The old *_cluster_* names still exist as deprecated aliases (banner in v1.1, hidden in v1.2, removed in v1.3) and can be used alternatively against a v1.1 server — but prefer the canonical form.
The resource toolset (dev-facing, enabled by default) covers Resource CRUD plus scope-collapsed reads on (Cluster)ResourceType. ResourceReleaseBinding and ProjectReleaseBinding CRUD both sit in the deployment toolset alongside ReleaseBinding. The resource_release_binding create/update calls are how a Resource gets deployed into an env (or promoted); project_release_binding create/update are the same for a project's cell. (Cluster)ProjectType is read-only here (list_project_types / get_project_type / get_project_type_schema, scope-aware) — authoring it is PE-side.
Working style
- Live cluster output beats memory. Discover via MCP first; don't guess available ComponentTypes / Traits / Workflows / Environments / field names.
- Schema-first authoring.
get_workload_schema, orget_component_type_schema/get_trait_schemawithscope: "cluster"for platform-wide standards, before writing a spec from scratch.
Stable guardrails
- All work goes through the control-plane MCP server. If a task can't be done via MCP, it's platform-side — hand off.
- Third-party / public apps: default to BYO image. Source builds commonly fail on third-party Dockerfiles using
ARG BUILDPLATFORM(exit 125). Switch to BYO immediately if you see it. - Before deploying any third-party app: fetch the official manifests and extract every required env var — dependencies inject service addresses but not
PORT, feature flags, or vendor SDK disable flags. - A handed-over migration plan is the spec. When the user supplies a migration/onboarding plan, take namespace, env var placement (static Workload env vs per-env
workloadOverrides), and wiring decisions from it. Deviate only out loud — state what you're changing and why before acting, never silently substitute. - Author types to fit the app — never re-shape the app to fit shipped types. When the plan (or the app) needs a
ComponentType/ResourceType/Traitthat isn't installed or that ships but doesn't meet the requirement, the fix is to author it — load../openchoreo-platform-engineer/SKILL.mdand create a fit-for-purpose type. Do not work around the gap by: re-modeling a managed dependency as a plain Component because the shippedResourceTypedoesn't fit (it's still a Resource — author aResourceTypethat reproduces what the dependency needs); dropping a capability the app needs because no shipped Trait provides it (author the Trait); or forcing the workload onto a shippedComponentTypewhose shape or defaults don't fit (author theComponentType). Reuse a shipped type only when it genuinely meets the contract. The needs drive the types, not the reverse. - Set resources from the source, not the ComponentType's defaults. Use the workload's source-declared requests/limits (CPU and memory). If the source declares none, pick a plausible default for the workload class — never inherit a generic CT's defaults, which are typically demo-grade and under-provision. When you author the CT, bake sensible defaults into its
environmentConfigs; otherwise set them via the ReleaseBinding's per-env config. - Injected connection values are literal — there is no
$(VAR)interpolation. DependencyenvBindingsinject each connection value (address/host/port/basePath) as the literal env var you name; the platform does not expand shell/Kubernetes$(VAR)references inside other env values, sovalue: "http://$(HOST):$(PORT)"reaches the container verbatim. Bind the exact env var the app reads. If the app needs a composed string the injected vars don't directly provide (a full URI, a barehost:portwith no scheme, a scheme prefix), set that composed value as a literal env var — typically a per-envworkloadOverrideusing the resolved address — rather than referencing$(VAR). - A missing tool means version skew, not absence. When a documented MCP tool isn't found, check the server version against the cluster before concluding the surface doesn't exist — report the mismatch to the user, then fall back or escalate.
Anti-patterns
- Skipping the recipe. Before any new operation (new CRD kind this turn, lifecycle action, runtime inspection) — re-scan the recipe index above, load the matching recipe (one Read call), THEN call MCP / kubectl. Skipping is how kubectl falls multiply and existing MCP tools get missed. Concept references aren't enough — recipes name the right tool calls in sequence.
- Running every discovery call before checking the resource already implicated.
- Writing specs from memory when
get_*_schema/get_*can reveal the current shape. - Guessing deployed URLs instead of reading
ReleaseBinding.status.endpoints[]. - Treating a platform-side failure as an app-only problem after the evidence points elsewhere.
- Creating source-build components for third-party apps that have pre-built images.
- Setting
visibility: externalon a service-to-service dependency in the same project —projectis the default. - Treating
Ready=Trueas "working". Ready means reconciled, not functional. A crash-looping container can flap Ready, and a stable container can be Ready while misconfigured (env vars bound to wrong names, deps resolving to nowhere). Confirm withget_resource_tree→get_resource_events/get_resource_logsand an actual endpoint hit.