Skip to content

How to execute a launch handoff packet from CI

How-to · Updated Sep 2026
Before this

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.yaml at your repository root that validates cleanly. See the quake.yaml reference.
  • 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 (or terraform), jq, and yq available.

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.

  1. Prepare. Convert quake.yaml to JSON and call the prepare_launch MCP tool with the manifest, an action, and the commit SHA. The response carries the handoff packet.
  2. Build. Run the commands in resolved.build.steps to build the image, push it to your registry, and record the pushed reference.
  3. Apply. Apply each entry in resolved.template_plan in apply_order (services before the runtime), binding the resolved variables and the runtime entry's container_env.
  4. Verify. Read the runtime template outputs (container_url, floating_ip) and confirm the workload responds.
YouRepositoryquake.yamlCI runnerMCP endpointdocs.quake.ai/api/mcpContainer registryQuake AI1. prepare_launch2. build + push3. tofu apply4. verify pushtriggermanifest + actionpush imageprovision
Click to zoom
A push triggers a CI job that prepares the packet against the MCP endpoint, then builds, applies, and verifies on the runner

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 eventLaunch actionEnvironment entry
Push or pull request on a feature branchpreviewpreview (for example branch: "*")
Merge to maindeployproduction (branch: main)

Store CI secrets#

Add these as repository or project secrets. Pass them by name into the job; do not commit values.

SecretPurpose
REGISTRY_USERNAME, REGISTRY_PASSWORDPush credentials for your container registry
OS_AUTH_URL, OS_APPLICATION_CREDENTIAL_ID, OS_APPLICATION_CREDENTIAL_SECRETOpenStack application credentials for the OpenTofu provider
SSH_KEY_NAMEName of the keypair that you registered in your project
Any manifest secrets[] namesThe 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.

YAML
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_url

The 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:

  1. Iterate resolved.template_plan sorted by apply_order. Apply each service entry first, binding the variables the entry lists.
  2. Read each service entry's provides outputs (for example a Postgres private_ip and database_url).
  3. Apply the runtime entry last. Set its container_env keys from the prior service outputs and from your manifest secrets[] values, then bind container_image to 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:

bash
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#

See also#

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

Was this page helpful?