Use this skill when the user wants an application deployed onto AgentDeploy, or when an existing AgentDeploy deployment needs to be updated or debugged.
Read
references/service-contract.md when writing or editing
or
.
Read
references/operations.md when running the CLI or handling failures.
Before using this skill, make sure
is installed and on
.
This is the current private macOS install path. If
is missing, direct the user to
brew.sh and wait for them to finish that install themselves before continuing. If
, GitHub auth, or
is still unavailable after that, stop and report the install blocker before attempting deploy commands.
The current CLI already carries the prototype Platform API URL and Entra scope by default. On the first API-backed command it will run its own Entra device-code login flow and cache the session token until it expires. You only need to set API flags or environment variables when overriding the installation defaults.
Treat
AGENTDEPLOY_CONFIG_REPO_REMOTE
as an explicit fallback only for intentional direct GitOps mode without the Platform API.
-
Confirm the CLI is available, then inspect the app before writing contracts.
- Run before using the workflow.
- Look for whether it serves HTTP, runs background work, or is purely scheduled.
- Check whether it already expects , , , or migration commands.
- Prefer reusing an existing immutable image digest. Use a block only when the user wants AgentDeploy to build from source.
-
Choose the application shape.
- If the app has exactly one service, no shared state, no
valueFrom.infrastructureRef
, and no , a single is enough.
- In that standalone shape, AgentDeploy can bootstrap , , and directly from the record.
- If multiple services need to share a namespace, PostgreSQL, Redis, object storage, or service-to-service wiring, create a record first and then point each service at it through .
- Treat as the only place that owns built-in DB, Redis, or object-storage resources. Do not put on a ; that model is gone.
-
Choose the workload shape for each service.
- : browser-facing app with HTTP ingress.
- : browser-consumed backend with HTTP ingress.
- : no ingress, background process.
- : scheduled job, no ingress.
-
Create or update the contracts.
- Start from when the app needs shared DB/Redis or multiple services.
- Start each service from the closest service template in .
- Keep the app name DNS-safe.
- If the repo does not already declare deploy metadata, derive a unique app name and subdomain from the repo or directory name so the deployment does not collide with an existing app.
- If is missing from repo context, prefer a real maintainer email from git config, docs, or project context. Only invent a synthetic owner for an explicit smoke test.
- If is missing from repo context, prefer an obvious team name from the repo, parent directory, or surrounding project docs. If none exists, choose a clearly temporary team name for a smoke test and call out the assumption.
- Default to
dataClassification: internal
unless the user explicitly says the data is more sensitive.
- Keep explicit on services when more than one service shares the same app.
- For a tiny standalone app, letting default to is fine.
- Default to unless the user explicitly needs public reachability.
- Default to
authorization.mode: group-based
unless the user explicitly wants and policy allows it.
- Prefer dedicated Entra security groups for app access. Use broader team-wide groups only when the whole team should be able to use the app.
- For smoke tests or lab installs without real group IDs, is acceptable only for apps and only when the installation policy allows it. Do not use it for sensitive data.
- If the user explicitly wants a fully public app with no shared auth at all, warn them first that the app will be reachable anonymously on the public internet and will not receive any shared identity headers.
- For that mode, use:
spec.dataClassification: public
spec.access.authorization.mode: none
- In the current policy set, unauthenticated app access is allowed only for
dataClassification: public
. Call out that the app will not receive identity headers in that mode.
- If the app needs PostgreSQL, declare it on under
spec.infrastructure.databases.<name>
and wire one of the DB env variants from valueFrom.infrastructureRef
:
- or for libpq / sync clients
- for common async Python stacks
- If the app needs Redis, declare it on under
spec.infrastructure.redis.<name>
and wire or from valueFrom.infrastructureRef
.
- If the app needs shared upload or document handoff storage across services, declare it on under
spec.infrastructure.objects.<name>
and wire it from valueFrom.infrastructureRef
with .
- For split API/worker document flows, prefer object storage plus object keys over local-path handoff. Keep local disk only for scratch via
runtime.filesystem.writablePaths
.
- If one service needs to call another service in the same application, wire that URL with instead of hardcoding domains or patching manifests.
- In the current prototype, Redis is only supported for
dataClassification: internal
.
- Make sure the process actually listens on . If the app expects a env var, set it explicitly.
- and are supported. Use them when the workload needs an explicit startup command instead of baking a wrapper image only for process launch.
- If the app needs writable ephemeral directories, use
runtime.filesystem.writablePaths
instead of asking users to patch manifests by hand.
- Only set
runtime.filesystem.readOnlyRootFilesystem: false
when the app genuinely cannot work with explicit writable mounts. Treat that as a security tradeoff and call it out.
-
Validate before deploying.
- Prefer the API-owned path when the installation provides it. The current CLI already defaults to the prototype API URL and Entra scope, so only set flags or environment variables when you need to override those defaults.
- Validate first when present, then validate each dependent .
- Run
agentdeploy validate --file <contract>.yaml
.
- If you intentionally want offline local-engine validation instead of the hosted API path, pass .
- Inspect or , plus and , in the response. They are the fastest way to catch dropped or mismatched fields before a deploy.
- For a standalone service-only app, should include , , and . If those files are absent, the app is no longer on the standalone bootstrap path.
- Treat errors as pre-flight failures against the current rendered namespace limits, not as generic rollout failures.
- Treat capacity-related warnings as best-effort scheduler signals. They do not block deploy by themselves, but they mean the cluster may be too full to place the new pods.
- Fix errors by following the exact , , and in the JSON response.
- Then run
agentdeploy deploy --file <contract>.yaml --dry-run
.
- In the current prototype, can still return and an . Treat it as preview-only. Review , or , , and rather than assuming a live deployment started.
-
Deploy for real.
- Deploy first when present, then deploy each dependent .
- Run
agentdeploy deploy --file <contract>.yaml
.
- Capture , the reported record name, and the initial phase.
- Do not assume or revision are returned immediately. Live deploys are queued and executed asynchronously.
- If local CLI mode returns , stop. Use the Platform API path or configure a real GitOps remote. Only use
AGENTDEPLOY_ALLOW_LOCAL_GITOPS=true
when the user explicitly wants local-only GitOps testing.
- If the deploy returns
DEPLOY_MISSING_SHARED_INFRA
, the app is not a true standalone service. Either deploy first or remove the extra shared-state / service-ref coupling.
- If the deploy is rejected with
DEPLOY_OPERATION_ALREADY_IN_PROGRESS
, check whether the active operation is still desirable. If it is stuck or obsolete, run agentdeploy cancel <record>
and then submit the replacement deploy.
- Poll with
agentdeploy status <record>
until the phase is or an error is returned.
-
Verify the result.
- Start with the aggregate application view for multi-service apps:
agentdeploy app-status <team> <application>
agentdeploy app-explain <team> <application>
- Use the aggregate view to confirm plus all dependent services are converging together before drilling into a single record.
- Use the URLs returned by or for services. Do not hardcode domains because each installation can differ.
- For a complete state dump, run
agentdeploy explain <record>
.
- For runtime debugging without , use:
agentdeploy describe <record>
for pod names, restart counts, waiting or termination reasons, image digests, requests, limits, and service or endpoint visibility
agentdeploy events <record>
for missing secrets, quota failures, probe failures, and scheduling errors
agentdeploy logs <record> [--follow] [--previous] [--pod <name>] [--container <name>] [--tail N]
for live or previous container logs
- In , inspect the live and sections when secret wiring or same-namespace traffic looks wrong.
- Compare against . If they differ, the control plane has accepted a newer revision than ArgoCD has actually reconciled in the cluster.
- Treat a stale-reconciliation warning as a real GitOps signal. The platform now requests a targeted Argo refresh automatically, and you can also run
agentdeploy refresh <app>
if the warning persists.
- If the app depends on PostgreSQL, confirm is healthy, the service injects the DB variant it actually uses, and the app-level readiness check matches the app’s real dependencies.
- If the app depends on Redis, confirm is healthy, the service injects or , and the app-level readiness check actually exercises Redis.
- If the app depends on shared object storage, confirm is healthy and the service injects the object-store keys it actually uses. Prefer for portable app wiring and fall back to only when the runtime still needs provider-specific compatibility.
- Remember that , , and are usually filtered by team-scoped control-plane RBAC, not by app owner alone.