initializdocs
Cli

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.
  • --image overrides the spec's image, so CI-templated tags need no yq/sed rewriting of the manifest.
  • With --wait the command polls until the rollout finishes — exit code 5 on failure, 6 on timeout. This is the CI-friendly mode.

agent deploy flags

FlagShorthandDefaultDescription
--file-finitializ-deploy.yamlPath to the deploy spec
--imageImage ref to deploy (overrides the spec's image)
--waitfalsePoll until the rollout finishes
--timeout0 (→ 10m)Max time to wait (Go duration, e.g. 15m)
--poll-interval0 (→ 5s)Status poll interval
--skip-env-checkfalseDon'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: 10m

Validation 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 marked optional: true, in which case it is omitted from the request entirely.
  • $$ escapes a literal $; a bare $ (not followed by {) is literal.
  • secret: true routes 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:

  1. .forge-output/build-manifest.json — the env_required / env_optional lists (structured; present in recent forge versions).
  2. .forge-output/k8s/secrets.yaml — the stringData: keys; a key preceded by a # optional comment line counts as optional (older forge versions).
  3. SKILL.md frontmatter (requirements.env.required / optional / one_of) when no .forge-output is present. one_of groups 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 building to success or failed; 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: --timeout flag, else the spec's deploy.timeout, else 10m. On expiry the command exits with code 6.
  • A failed status exits with code 5 and prints the server-side error (or points you at initializ 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

On this page