agent deploy
Deploy a CI-built agent image to the initializ AI Platform — the deploy spec, forge.yaml and build-output inputs, env var interpolation, and --wait semantics.
initializ agent deploy submits a CI-built agent image to the platform. It
composes a deploy request from initializ-deploy.yaml, forge.yaml, the
repo's SKILL.md files, and the forge build output directory
(.forge-output), then submits it. The platform renders the Kubernetes
manifests and rolls the agent — the image must already be pushed to the
workspace Environment's registry by your CI job.
initializ agent deploy -f initializ-deploy.yaml [--image <ref>] [--wait]Key semantics:
- Upsert on (workspace, agent name): the first deploy creates the agent, later deploys update it.
--imageoverrides the spec'simage, so CI-templated tags need noyq/sedrewriting of the manifest.- With
--waitthe command polls until the rollout finishes — exit code 5 on failure, 6 on timeout. This is the CI-friendly mode.
agent deploy flags
| Flag | Shorthand | Default | Description |
|---|---|---|---|
--file | -f | initializ-deploy.yaml | Path to the deploy spec |
--image | Image ref to deploy (overrides the spec's image) | ||
--wait | false | Poll until the rollout finishes | |
--timeout | 0 (→ 10m) | Max time to wait (Go duration, e.g. 15m) | |
--poll-interval | 0 (→ 5s) | Status poll interval | |
--skip-env-check | false | Don't fail on missing required env vars |
All global flags apply. The target workspace is
resolved in this order: --workspace / INITIALIZ_WORKSPACE_ID / config
file, then the spec's agent.workspace, then the workspace baked into the
token. If none resolves, the command fails with exit code 2.
The deploy spec (initializ-deploy.yaml)
The spec lives in the agent's git repo next to forge.yaml. Fully annotated:
apiVersion: initializ.ai/v1
kind: AgentDeploy
agent:
# Display/lookup name on the platform. Deploys are an UPSERT keyed on
# (workspace, name). Defaults to forge.yaml's agent_id when omitted.
name: support-agent
# Agent runtime type. v1 supports "forge" (the default).
type: forge
# Workspace id (ws_…). Optional — falls back to --workspace,
# INITIALIZ_WORKSPACE_ID, then the workspace baked into the token.
# workspace: ws_a1b2c3de
# Image your CI just built & pushed to the registry configured on the
# workspace's Environment. --image overrides this.
image: registry.initializ.ai/acme/support-agent:latest
forge:
# Path to forge.yaml, relative to this file. Default: ./forge.yaml
path: ./forge.yaml
# forge build output — the CLI reads the image's declared env-var union
# from build-manifest.json (or k8s/secrets.yaml). Default: ./.forge-output
outputDir: ./.forge-output
# Environment variables for the agent container.
env:
- name: LOG_LEVEL
value: info
- name: OPENAI_API_KEY
value: ${OPENAI_API_KEY} # interpolated from the CI environment
secret: true # lands only in the agent's Kubernetes Secret
- name: FEATURE_FLAG_X
value: ${FEATURE_FLAG_X}
optional: true # silently omitted when ${FEATURE_FLAG_X} is unset
# Optional container port when the agent doesn't listen on forge's default 8080.
# port: 9000
# Optional runtime sizing; omitted fields use platform defaults.
resources:
replicas: 1
requests: {cpu: 250m, memory: 256Mi}
limits: {cpu: "1", memory: 1Gi}
# Extra egress domains merged additively with forge.yaml's
# egress.allowed_domains and skill-declared egress domains.
egress:
additionalDomains:
- api.stripe.com
# Default deploy behavior (flags always win).
deploy:
wait: true
timeout: 10mValidation rules (violations exit with code 2): apiVersion must be
initializ.ai/v1 when set, kind must be AgentDeploy when set,
agent.type must be forge when set, port must be 0–65535, and every
env entry needs a non-empty name.
Env value interpolation
env[].value supports ${VAR} interpolation from the CI process
environment only — secret values live in the CI secret store, never in the
file. Interpolation applies exclusively to env[].value; the rest of the
document (image, name, egress) stays literal, so what gets deployed is
auditable from the file plus the --image flag alone.
- An unresolvable
${VAR}reference fails the deploy with exit code 2 — unless the entry is markedoptional: true, in which case it is omitted from the request entirely. $$escapes a literal$; a bare$(not followed by{) is literal.secret: trueroutes the value into the agent's Kubernetes Secret only — the platform never persists it.
The env-var contract check
The CLI knows which env vars the image requires — the union of skill
requirements, channel vars, and model-provider keys computed at
forge build time — and fails fast (exit 2) when a required var is neither in
env: nor provided as a secret. Source-of-truth order:
.forge-output/build-manifest.json— theenv_required/env_optionallists (structured; present in recent forge versions)..forge-output/k8s/secrets.yaml— thestringData:keys; a key preceded by a# optionalcomment line counts as optional (older forge versions).SKILL.mdfrontmatter (requirements.env.required/optional/one_of) when no.forge-outputis present.one_ofgroups are treated as optional so they display without causing false failures.
--skip-env-check downgrades a missing required var from a local exit-2
failure to a platform-side warning (the platform re-checks anyway).
Skill discovery
The CLI lifts display and policy metadata (name, description, category,
declared env requirements, egress domains) from the repo's skill files,
mirroring forge's own discovery rules: skills/*.md, skills/*/SKILL.md,
plus the file named by forge.yaml's skills.path (default SKILL.md).
What is read from forge.yaml
From forge.yaml the CLI lifts: agent_id (required — also the default
agent name), version, framework, model.provider / model.name,
egress.mode / egress.allowed_domains, channels, skills.path, audit
capture settings, and compression. The exact file bytes are also uploaded for
provenance. Unknown fields never break a deploy.
CI provenance
When running under GitHub Actions or GitLab CI, the CLI auto-detects provenance metadata (provider, commit SHA, run URL) from the standard CI env vars and attaches it to the deploy for display on the platform.
Waiting for the rollout
With --wait (or deploy.wait: true in the spec) the command polls the
agent's deploy status until it is terminal:
- Statuses progress through
buildingtosuccessorfailed; each transition is printed to stderr (suppressed by--quiet). - Poll interval defaults to 5s (with jitter so parallel CI jobs don't
stampede the API); override with
--poll-interval. - Timeout resolution:
--timeoutflag, else the spec'sdeploy.timeout, else 10m. On expiry the command exits with code 6. - A
failedstatus exits with code 5 and prints the server-side error (or points you atinitializ agent logs). - Transient errors (network, 5xx) are tolerated up to 5 consecutive polls; auth or not-found errors abort immediately.
Without --wait, the command prints the deploy id to stdout and returns as
soon as the platform accepts the request (the rollout continues
asynchronously).
Deploy output
Text mode (progress on stderr, result on stdout):
deploying support-agent (image registry.initializ.ai/acme/support-agent:sha-1a2b3c4) to workspace ws_a1b2c3de…
accepted: agent agt-42 deploy dep-777
status: building
status: success
deployed agt-42 (registry.initializ.ai/acme/support-agent:sha-1a2b3c4)With -o json and --wait, one JSON document goes to stdout:
{
"agent_id": "agt-42",
"deploy_id": "dep-777",
"status": "success",
"image": "registry.initializ.ai/acme/support-agent:sha-1a2b3c4",
"warnings": []
}Without --wait, -o json prints the acceptance response
(agentId, deployId, status, created, warnings); text mode prints
just the deploy id.
Complete GitHub Actions workflow
name: deploy-agent
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install forge
run: |
curl -fsSL https://github.com/initializ/forge/releases/latest/download/forge-Linux-x86_64.tar.gz \
| tar xz && sudo mv forge /usr/local/bin/
# forge build generates .forge-output/ (Dockerfile, build-manifest.json,
# k8s templates) — the CLI reads the env-var contract from it.
- name: forge build
run: forge build
- uses: docker/login-action@v3
with:
registry: registry.initializ.ai
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- uses: docker/build-push-action@v6
with:
context: .forge-output
push: true
tags: registry.initializ.ai/acme/support-agent:sha-${{ github.sha }}
- name: Install initializ CLI
run: |
curl -fsSL https://github.com/initializ/cli-next/releases/latest/download/initializ_linux_amd64.tar.gz \
| tar xz && sudo mv initializ /usr/local/bin/
- name: Deploy to initializ
env:
INITIALIZ_API_URL: https://api.initializ.ai
INITIALIZ_TOKEN: ${{ secrets.INITIALIZ_TOKEN }}
INITIALIZ_ORG_ID: ${{ vars.INITIALIZ_ORG_ID }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
initializ auth whoami
initializ agent deploy -f initializ-deploy.yaml \
--image "registry.initializ.ai/acme/support-agent:sha-${{ github.sha }}" \
--wait --timeout 10m