Skip to content

Building Custom Images

Scion agents run inside container images that bundle an LLM harness (Claude, Gemini, etc.) with the Scion toolchain. By default, Scion uses pre-built images from the upstream registry. This guide shows how to build your own images and configure Scion to use them.

  • Self-hosted registries: Push images to a registry you control (GHCR, Artifact Registry, ECR, etc.).
  • Pinned versions: Tag and version images to match your deployment lifecycle.
  • Custom modifications: Add tools, certificates, or configurations to the base images.

Scion images are built in layers:

core-base System dependencies (Go, Node, Python, Git)
└── scion-base Scion CLI, sciontool binary, scion user, entrypoint
├── scion-claude Claude Code harness
├── scion-gemini Gemini CLI harness
├── scion-opencode OpenCode harness
└── scion-codex Codex harness

The core-base layer changes infrequently. Most rebuilds only need scion-base and the harness layers (the common build target).

Build images locally and push to your registry:

Terminal window
# Build scion-base + all harness images, then push
image-build/scripts/build-images.sh --registry ghcr.io/myorg --push
# Configure Scion to use them
scion config set image_registry ghcr.io/myorg

If your project is hosted on GitHub:

  1. Fork the repo (or use it as a template).
  2. Go to Actions > Build Scion Images > Run workflow.
  3. Enter ghcr.io/<your-username> as the registry.
  4. Wait for the build to complete.
  5. Configure Scion:
    Terminal window
    scion config set image_registry ghcr.io/<your-username>

The workflow builds multi-platform images (linux/amd64 and linux/arm64) and pushes them to GHCR using the repository’s GITHUB_TOKEN.

For GCP-based workflows:

Terminal window
# One-time setup: enable APIs, create Artifact Registry repo, grant permissions
image-build/scripts/setup-cloud-build.sh --project my-gcp-project
# Trigger a build
image-build/scripts/trigger-cloudbuild.sh --project my-gcp-project

Then configure Scion with the registry path printed by the setup script:

Terminal window
scion config set image_registry us-central1-docker.pkg.dev/my-gcp-project/scion

The image_registry setting tells Scion to pull images from your registry instead of the upstream default. It rewrites the registry prefix of all standard harness images (those named scion-<harness>) while preserving the image name and tag.

When image_registry is set, Scion transforms the default image reference:

Default Imageimage_registryResolved Image
us-central1-docker.pkg.dev/.../scion-claude:latestghcr.io/myorgghcr.io/myorg/scion-claude:latest
us-central1-docker.pkg.dev/.../scion-gemini:latestghcr.io/myorgghcr.io/myorg/scion-gemini:latest

Globally (applies to all groves):

Terminal window
scion config set image_registry ghcr.io/myorg

Or edit ~/.scion/settings.yaml directly:

schema_version: "1"
image_registry: "ghcr.io/myorg"

Per-profile (different registries for different environments):

profiles:
local:
runtime: docker
image_registry: "ghcr.io/myorg"
staging:
runtime: kubernetes
image_registry: "us-central1-docker.pkg.dev/myproject/staging"

Profile-level image_registry takes precedence over the top-level setting.

The image_registry setting is the lowest-priority way to configure images. Explicit overrides always win:

  1. CLI --image flag (highest priority)
  2. Template scion-agent.yaml image field
  3. Profile harness_overrides image field
  4. image_registry rewrite (lowest priority)

If any higher-priority override specifies a full image path, image_registry does not apply to that agent.

The image-build/scripts/build-images.sh script supports the following options:

FlagDescriptionDefault
--registry <path>Required. Target registry path (e.g., ghcr.io/myorg).
--target <target>Build target: common, all, core-base, or harnesses.common
--pushPush images after building.Build only
--platform <plat>Target platform(s). Use all for linux/amd64,linux/arm64.Current arch
--tag <tag>Image tag.latest
TargetWhat It Builds
commonscion-base + all harness images (assumes core-base already exists).
allFull rebuild: core-base + scion-base + all harnesses.
core-baseOnly the core-base layer.
harnessesOnly the harness images (assumes scion-base already exists).
Terminal window
# Full rebuild for all platforms, pushed to GHCR
image-build/scripts/build-images.sh \
--registry ghcr.io/myorg \
--target all \
--platform all \
--push
# Build only harness images with a specific tag
image-build/scripts/build-images.sh \
--registry ghcr.io/myorg \
--target harnesses \
--tag v1.2.0 \
--push
# Local build for testing (no push, current architecture only)
image-build/scripts/build-images.sh \
--registry local/test

The workflow at .github/workflows/build-images.yml can be used in two ways:

Run it from the GitHub Actions UI with inputs for registry, target, tag, and platform.

Call it from your own workflows in downstream repos:

jobs:
build-images:
uses: google/scion/.github/workflows/build-images.yml@main
with:
registry: ghcr.io/myorg
target: common
tag: latest
platform: all

Scion includes Cloud Build configuration files for GCP-native builds:

Config FilePurpose
cloudbuild.yamlFull rebuild of all layers.
cloudbuild-common.yamlRebuild scion-base + harnesses (most common).
cloudbuild-core-base.yamlRebuild core-base only.
cloudbuild-harnesses.yamlRebuild all harness images only.

Run the one-time setup script to configure your GCP project:

Terminal window
image-build/scripts/setup-cloud-build.sh --project my-gcp-project

This script:

  • Enables the Cloud Build and Artifact Registry APIs.
  • Creates an Artifact Registry repository named scion.
  • Grants Cloud Build the necessary IAM permissions.
Terminal window
# Build everything (default: cloudbuild-common.yaml)
image-build/scripts/trigger-cloudbuild.sh --project my-gcp-project
# Full rebuild including core-base
image-build/scripts/trigger-cloudbuild.sh --project my-gcp-project --config cloudbuild.yaml