How to execute a launch handoff packet from CI
How to execute a launch handoff packet from CI
Run a CI job that turns your repository's quake.yaml into a running deployment. Call the prepare_launch MCP tool to get a handoff packet, build and push the image from the resolved build recipe, apply the templates in resolved.template_plan order, and read the runtime outputs to verify the deployment.
This page provides GitHub Actions and GitLab CI workflows. Quake AI does not host CI runners; use the provider's hosted runners or a self-hosted runner on a Quake AI VM.
Prerequisites
- A
quake.yamlat your repository root that validates cleanly. See thequake.yamlreference. - A container registry the target instance can pull from, and push credentials for it.
- An SSH keypair that you registered in your Quake AI project, and application credentials for the OpenStack provider.
- A CI runner with
docker,tofu(orterraform),jq, andyqavailable.
How the packet flows through a pipeline#
A pipeline run carries the manifest through four stages. The hosted MCP endpoint handles the first stage, and your CI runner handles the remaining stages.
- Prepare. Convert
quake.yamlto JSON and call theprepare_launchMCP tool with the manifest, an action, and the commit SHA. The response carries the handoff packet. - Build. Run the commands in
resolved.build.stepsto build the image, push it to your registry, and record the pushed reference. - Apply. Apply each entry in
resolved.template_planinapply_order(services before the runtime), binding the resolvedvariablesand the runtime entry'scontainer_env. - Verify. Read the runtime template outputs (
container_url,floating_ip) and confirm the workload responds.
Map branches to launch actions#
Pick the launch action from the git ref so feature branches preview and main deploys. The action selects which environment entry the packet resolves: preview requires a preview environment, and deploy requires a production environment.
| Git event | Launch action | Environment entry |
|---|---|---|
| Push or pull request on a feature branch | preview | preview (for example branch: "*") |
Merge to main | deploy | production (branch: main) |
Store CI secrets#
Add these as repository or project secrets. Pass them by name into the job; do not commit values.
| Secret | Purpose |
|---|---|
REGISTRY_USERNAME, REGISTRY_PASSWORD | Push credentials for your container registry |
OS_AUTH_URL, OS_APPLICATION_CREDENTIAL_ID, OS_APPLICATION_CREDENTIAL_SECRET | OpenStack application credentials for the OpenTofu provider |
SSH_KEY_NAME | Name of the keypair that you registered in your project |
Any manifest secrets[] names | The application secret values the runtime reads, supplied by name |
The prepare_launch endpoint itself needs no authentication. The credentials above authenticate the build and apply stages, which run on your runner.
The pipeline#
The workflow below prepares the packet, builds and pushes the image, applies the containerized-app runtime, and verifies. It uses a single-template manifest (runtime: container, no services[]); the section after it covers manifests that declare backing services.
name: Launch from quake.yaml
on:
push:
branches: [main]
pull_request:
jobs:
launch:
runs-on: ubuntu-latest
env:
REGISTRY: registry.example.com/my-team
OS_AUTH_URL: ${{ secrets.OS_AUTH_URL }}
OS_APPLICATION_CREDENTIAL_ID: ${{ secrets.OS_APPLICATION_CREDENTIAL_ID }}
OS_APPLICATION_CREDENTIAL_SECRET: ${{ secrets.OS_APPLICATION_CREDENTIAL_SECRET }}
steps:
- uses: actions/checkout@v4
- name: Choose the launch action
run: |
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
echo "ACTION=deploy" >> "$GITHUB_ENV"
else
echo "ACTION=preview" >> "$GITHUB_ENV"
fi
- name: Prepare the handoff packet
run: |
yq -o=json '.' quake.yaml > manifest.json
jq -n \
--slurpfile m manifest.json \
--arg action "$ACTION" \
--arg sha "$GITHUB_SHA" \
'{jsonrpc:"2.0",id:1,method:"tools/call",
params:{name:"prepare_launch",
arguments:{manifest:$m[0],action:$action,source_sha:$sha}}}' \
> rpc.json
curl -sS https://docs.quake.ai/api/mcp \
-H 'Content-Type: application/json' \
-d @rpc.json \
| jq '.result.structuredContent.content' > packet.json
jq -e 'has("resolved")' packet.json > /dev/null \
|| { echo "prepare_launch failed:"; cat packet.json; exit 1; }
- name: Build and push the image
run: |
printf '%s' "${{ secrets.REGISTRY_PASSWORD }}" \
| docker login "$REGISTRY" \
--username "${{ secrets.REGISTRY_USERNAME }}" \
--password-stdin
IMAGE="$REGISTRY/$(jq -r '.manifest.name' packet.json):${GITHUB_SHA::12}"
docker build -t "$IMAGE" -f "$(jq -r '.resolved.build.dockerfile // "Dockerfile"' packet.json)" .
docker push "$IMAGE"
echo "IMAGE=$IMAGE" >> "$GITHUB_ENV"
- name: Apply the runtime template
run: |
tofu -chdir=iac/templates/containerized-app init
tofu -chdir=iac/templates/containerized-app apply -auto-approve \
-var "flavor_name=$(jq -r '.resolved.template_plan[] | select(.role == "runtime") | .variables.flavor_name.value' packet.json)" \
-var "app_name=$(jq -r '.manifest.name' packet.json)" \
-var "key_name=${{ secrets.SSH_KEY_NAME }}" \
-var "container_image=$IMAGE"
- name: Verify
run: |
tofu -chdir=iac/templates/containerized-app output -raw container_urlThe build step follows the packet's build method and Dockerfile, then replaces the packet's registry placeholder with your registry and a commit-specific image tag. Fetch the template source with the get_template MCP tool or vendor it into the repository under iac/templates/, the path the packet references.
Manifests that declare backing services#
When the manifest declares services[] (Postgres, Redis, object storage, or a vector store), the packet lists each service as its own entry in resolved.template_plan with an apply_order lower than the runtime. Apply them in that order so the runtime can read their outputs:
- Iterate
resolved.template_plansorted byapply_order. Apply eachserviceentry first, binding thevariablesthe entry lists. - Read each service entry's
providesoutputs (for example a Postgresprivate_ipanddatabase_url). - Apply the
runtimeentry last. Set itscontainer_envkeys from the prior service outputs and from your manifestsecrets[]values, then bindcontainer_imageto the image you pushed.
Connection-string passwords stay name-only in the manifest. Declare them in secrets and inject the values from your CI secret store. The packet marks values that your pipeline must supply with value: null and a source note, so a script can walk the plan and fail early when a required binding is missing.
Verify the result#
After the apply stage, read the runtime outputs and check the workload:
tofu -chdir=iac/templates/containerized-app output -raw container_url
curl -fsS "$(tofu -chdir=iac/templates/containerized-app output -raw container_url)/healthz"A successful health check confirms the image runs and the instance is reachable. Record the deploy id, the resolved outputs, and the gate results in the packet's evidence_bundle if you keep an audit trail.
Next steps#
- Deploy an app to Coolify from a quake.yaml manifest: run the packet through a PaaS consumer instead of raw OpenTofu
- Run a push-to-webhook deploy without a CI server: the lightweight executor for small projects
- CI/CD pipelines: the broader build, test, and ship pattern on Quake AI
See also#
- Launch handoff: the manifest, the packet, and the branch workflow
quake.yamlreference: the manifest fields and resolution rules- How to integrate OpenTofu with CI/CD: plan and apply OpenTofu state from a pipeline
- How to deploy an application to a Quake AI VM from CI: ship code to an existing instance over SSH
Usage Guidelines
The sample code, software libraries, command line tools, proofs of concept, templates, and other related technology on this page (including any of the foregoing that is provided by Quake AI personnel) is provided to you as Quake AI Content under the Quake AI Customer Agreement, or the relevant written agreement between you and Quake AI (whichever applies). Do not use this Quake AI Content in your production accounts, or on production or other critical data. You are responsible for testing, securing, and optimizing the Quake AI Content (such as sample code) as appropriate for production grade use based on your specific quality control practices and standards. Deploying Quake AI Content may incur Quake AI charges for creating or using Quake AI chargeable resources, such as running Compute instances or storing data in Object Storage. Your use is also subject to the Acceptable Use Policy.
For the full policy, see Usage Guidelines.
Last validated: 01.09.2026
See Also
How to deploy from a Quake.yaml manifest with Forgejo Actions
Shares: Mcp, Quake Yaml
Launch handoff
Shares: Mcp, Quake Yaml
Deploy Coolify from a Quake.yaml manifest
Shares: Mcp, Quake Yaml
How to deploy on git push with a webhook listener
Shares: Quake Yaml, Launch
quake.yaml reference
Shares: Quake Yaml, Launch