Deploy an Application
deploy_applicationDeploy a multi-container application onto Cycle. You supply the app knowledge (image, command, env, ports, volumes, how many members and how they address each other); the tool turns it into a Cycle stack spec, creates and builds the stack, and deploys it into an environment. For a workload that truly needs a full virtual machine use deploy_virtual_machine.
Modes: by default everything deploys through a stack (containers that version and deploy together). One application is ONE call and one stack: every container it needs — data nodes, UI, sidecars — goes in the same 'containers' list. Containers are created stopped, so "incremental" means starting and checking them one at a time afterwards, not deploying them in separate calls; a stack cannot be extended with more containers later. Separate stacks are for independent applications that release on their own. stack:false creates one-off containers directly in the environment with no stack objects. Every rule below applies to both.
Existing stacks: a call with 'containers' ALWAYS creates a new stack. When the user names a stack that already exists — built by this tool, the dashboard, or from a git repo — pass stack_id instead and leave 'containers' out (or pass the original list only to link domains). It deploys the stack's latest usable build into the environment; build_id picks a specific build, rebuild:true generates a fresh build from the stack's source first. Containers the stack already has in that environment are left untouched unless 'redeploy' says to update them — rebuild:true plus redeploy:{reimage:true} is how a new image tag or commit is rolled out to a running deployment. preview:true reports the stack's recent builds, the containers the chosen build creates, and which existing ones would be updated.
MUST GET RIGHT — Cycle accepts these and the application is then silently unreachable or insecure. Preview checks them and an error finding blocks the deploy:
Listen on ::. The private network is IPv6-ONLY (discovery serves AAAA records) and the load balancer reaches backends over it, so a process on 0.0.0.0 or localhost is unreachable from siblings and from the LB. IPv4-default apps need IPv6 enabled explicitly (mongod --ipv6, HOST=::), and so do client libraries (Node's ioredis needs ?family=6 on the URL).
TLS through the LB needs BOTH "443:" and "80:80" in ports. "443:80" is Cycle notation: LB ingress 443 routes to backend 80 with TLS terminated at the LB.
Secrets never go in env or args — both are stored in plain text in the stack. Sequence: deploy (containers are created stopped) → create scoped variables with manage_scoped_variable and source.secret:true → start with cycle_control_container. First boot reads them (postgres initdb reads POSTGRES_PASSWORD once; redis needs its config file present).
Stateful containers deploy as a SINGLE instance with their own volume. Model a clustered app as N separate single-instance stateful containers (mongo-0, mongo-1, ...), each with its own volume and unique hostname. Containers reach each other by hostname; the environment must be live for discovery to resolve them.
Placement is unconstrained by default — a container may land on ANY server whose pool allows it, so cluster members can spread across providers. Pin hardware with constraints.node.tags.all (every tag present) or .any, and confirm the tag exists with list_servers BEFORE deploying; a tag matching no server leaves the container with no deployment target.
public defaults to "disable". Set it only to expose a container.
Images — each container sets exactly ONE of: image (a Docker Hub target like 'mongo:7'; an existing image source with the same origin is reused), image_source (already on Cycle — prefer it whenever the user has one, it carries their registry credentials and build config), or dockerfile (repo or targz_url for Cycle to build). Registry and git credentials are never accepted directly.
Backups — 'backups' (stateful containers only) has Cycle run 'command' on the cron 'schedule' inside the container and ship its STDOUT to a backup-capable hub integration ('destination', e.g. Backblaze B2); 'restore_command' reads a backup from STDIN. All four are required; the destination must already be enabled on the hub. Commands may reference env vars (mongodump -u $USER) but the tools they call must exist in the image.
Domains — 'domain' exposes a container through the environment load balancer. A DNS zone covering it must already exist; the tool creates a LINKED record pointing at the container and never overwrites an existing one (conflicts are errors to resolve with the user). Forces public:"enable" and requires ports; TLS on the record follows from a '443:' mapping. Cycle creates the environment load balancer only when the environment's services start with a public container present, so after deploying public containers into an environment without one the tool starts the environment's services itself; if that fails the response carries 'load_balancer_missing'.
'application' hint — pass an app name with NO containers to get recommended per-container config, topology, and caveats, then compose the container list from it. Unknown names return the known names instead of an error.
Workflow: 1) call with preview:true — returns the exact spec that would deploy plus checklist findings, and makes NO changes. 2) Confirm with the user, then call again without preview. Never deploy without explicit confirmation.
Asynchronous and RESUMABLE: containers appear only at the last step, so an early empty list_containers means "still working". Every response carries stack/build/job ids, 'phase', and 'recommended_action'. After a transport failure, repeat the call with the same name/deployment_id and follow 'recommended_action' ('wait', 'resume' with stack_id, or 'nothing_to_do'). A stack_id call is idempotent at every phase.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Stack name; also the default container prefix. | |
| stack | No | Default true: deploy via a Cycle stack. false: create or reuse the image source, import the image, and create the container(s) directly in the environment with no stack or build. Preview and domains work the same in both modes. | |
| context | No | Why are you calling this tool? Briefly describe the user's goal. | |
| preview | No | Return the spec that would deploy plus checklist findings, making NO changes. Always run this first to confirm intent with the user. | |
| rebuild | No | With stack_id: create and generate a fresh build from the stack's source before deploying, even when a live build exists (picks up new image tags or repo commits). Default false reuses the latest build; only a failed or deleted latest build is replaced. | |
| build_id | No | With stack_id: deploy this specific build instead of the latest. A failed or deleted build is rejected. | |
| redeploy | No | With stack_id, when the stack's containers already exist in the environment: update them to the chosen build. At least one of reimage/reconfigure must be true. Containers in the build that are missing from the environment are created either way. | |
| stack_id | No | Deploy an EXISTING stack (ID, identifier, resource path, or name) into 'environment' instead of creating one — to reuse a stack the user already has, or to continue an interrupted deployment. Picks up from the chosen build's current state (generate, deploy, containers, DNS) without redoing completed steps. 'containers' is optional here and only used to link domains. Not combinable with stack:false. | |
| containers | No | The containers to deploy. Compose these yourself; use the 'application' hint for guidance. | |
| application | No | Optional app-hint name, free-form. Curated hints: elasticsearch, mongodb, postgres, redis; other names return no hint (not an error). With no 'containers', returns the hint instead of deploying. | |
| environment | Yes | Target environment (must already exist). | |
| wait_seconds | No | Max seconds this call blocks on the deploy pipeline (default 60). 0 submits the next step and returns immediately. Every response carries stack/build/job ids and 'phase', so a later call with stack_id continues from wherever this one stopped. | |
| checklist_ack | No | Checklist error codes from a preview (e.g. 'listener.ipv4-bind') to deploy in spite of. Only after telling the user exactly what the finding says will break; an unacknowledged error blocks the deploy. | |
| deployment_id | No | Idempotency key (lowercase slug) used as the stack identifier; defaults to a slug of name. A repeat call with the same key refuses to create a duplicate stack and reports the existing one with the ids needed to resume. Pass a fresh value to deliberately create a separate stack. | |
| conversation_id | No | Conversation tracking id. Omit on your first tool call; every result then includes a conversation_id line — pass that exact value on all later calls in this conversation. |