Ionize Docs
Internalsionctl

Octl, stack bundle

How ionctl ships platform configs inside its npm package

@nannier/ionctl is the local-development CLI. To make npx @nannier/ionctl deploy work from any empty directory, the package bundles all the platform configs it needs.

What's in the bundle

ionctl/stack/:

  • compose.dev.yml, the dev Compose file.
  • ciam-kratos/kratos.yml, identity schemas
  • iam-kratos/kratos.yml, identity schemas
  • ciam-hydra/hydra.yml
  • iam-hydra/hydra.yml
  • Caddyfile, dev variant
  • init-db.sql
  • iam-seed-dev.sh
  • pgadmin-claims-mapper.jsonnet

These are vendored copies of the corresponding files in platform/dev/.

Why vendor

Two alternatives:

  1. Have ionctl clone the platform repo at runtime. Requires network, requires the user to authenticate.
  2. Vendor the files inside the package.

Vendoring is simpler. npx @nannier/ionctl deploy runs offline (once images are cached).

The trade-off: bundle drift. If platform/dev/ changes and the ionctl bundle isn't synced, dev environments differ from prod expectations.

Syncing the bundle

ionctl/scripts/sync-stack.sh:

#!/usr/bin/env bash
set -euo pipefail

REF=${1:-main}   # platform git ref to sync from

cd $(mktemp -d)
git clone --depth 1 --branch "$REF" https://github.com/bnannier/platform .
cp -r dev/* "$OCTL_ROOT/stack/"

cd "$OCTL_ROOT"
bun run typecheck   # ensure the new bundle still works with ionctl's code

Run via:

cd ionctl
bun run sync-stack -- v1.5.2  # or main

CI runs this before publishing ionctl to ensure the bundle is fresh against the platform commit being pinned.

Bundle version tracking

ionctl/stack/PLATFORM_REF records the platform git ref the bundle was synced from:

v1.5.2
abc123def456...   # commit SHA

When publishing ionctl, this is committed alongside.

Bundle vs platform divergence

If you've made local changes to platform/dev/ for testing, those don't go through ionctl. The dev stack via ionctl deploy uses the bundled configs, not the local ones.

To test local platform changes:

cd platform/dev
podman compose -f compose.dev.yml up -d

Skip ionctl entirely; run compose directly.

What ionctl deploy does at runtime

  1. Checks for Podman; installs if missing (macOS Homebrew).
  2. podman machine init + podman machine start if needed.
  3. Reads bundled compose.dev.yml.
  4. Generates .env.dev with development secrets (deterministic for dev, same value across runs of ionctl deploy so caches work).
  5. Runs podman compose up -d.
  6. Polls healthchecks.
  7. Prints access URLs + test credentials.

.env.dev contains:

  • ENCRYPTION_KEY, a dev-safe value (not on the blocklist).
  • SESSION_SIGNING_KEY, similarly.
  • Per-domain reload API keys.
  • Empty Turnstile (captcha disabled).
  • Pointers to MailSlurper (no real email).

When the bundle becomes stale

Symptoms:

  • ionctl deploy succeeds but Dashboard says "schema not found."
  • Identity schema mismatch between dev and prod.
  • New Kratos features don't work in dev.

Fix: bump ionctl. The maintainer publishes new ionctl versions as platform evolves.

On this page