Container images

The Future AGI images: what each runs, tags, sizes, labels, health checks, users, base images and build arguments, and how to verify one.

In this page

Every Future AGI image is published to Docker Hub under futureagi/, built from the future-agi repository by its release workflow, and follows the same conventions: one tag scheme, the same OCI labels, a digest-pinned base, a HEALTHCHECK that probes the service’s real health endpoint, and a documented user. This page lists every image, what it runs and how big it may be, and the conventions they share, so you can pin, verify, probe and rebuild them.

📝
TL;DR

Standalone pulls one Future AGI image, futureagi/standalone, next to Postgres and ClickHouse; Distributed and Helm run one image per service. The backend comes in two variants: the default, feature-complete one for Distributed and Helm, and a slim one inside Standalone. Pin a release tag (vX.Y.Z) or its digest for anything others rely on. Every image carries OCI labels with its release and the commit it was built from; the images are not signed yet.

Images at a glance

Setups: Standalone is the default install (./bin/install, docker-compose.yml). Distributed runs one container per service (./bin/install --distributed, docker-compose.distributed.yml). Helm is Distributed on Kubernetes and uses the same images.

Size budget: the most a docker pull may download (compressed MB, 10^6 bytes, per architecture), from scripts/image_size_budget.json. A release checks it on every architecture before it moves a tag.

ImageWhat it runsSetupsPortsUserHealth checkArchitecturesSize budget (MB)
futureagi/standaloneThe Standalone app container: API with an embedded Temporal worker, Temporal dev server, fi-collector, agentcc-gateway, code-evals sandbox, UI, Redis and object storage under supervisord. Built on the -slim backendStandalone3000 UI, 8000 API, 4317/4318 OTLP, 8080 gateway, 9005 object storagerootthe five URLs of the compose app healthcheckamd64, arm64549 (measured 479)
futureagi/future-agiBackend, the default variant (feature-complete): API (SERVICE_TYPE=backend), Temporal and Celery workers, bootstrap jobs. Base of the simulation runner and of the EE and cloud imagesDistributed, Helm80 HTTP, 50051 gRPC, 5555 Flowerroot (runs as 1000:1000 on request)GET /health/ on :80 for the API; roles with no listener are healthy while they runamd64, arm641015
futureagi/future-agi:*-slimThe same backend, lean: the base of futureagi/standaloneStandalone (inside futureagi/standalone)as aboveas aboveas aboveamd64, arm64376 (measured 341)
futureagi/frontendThe web UI: the React app served by nginxDistributed, Helm (Standalone serves the same files from futureagi/standalone)80root master, nginx (101) workersGET / on :80amd64, arm6442 (measured 37.6)
futureagi/fi-collectorOTLP receiver that writes spans to ClickHouse; also fi-property-catalog-consumer and fi-observed-catalog-backfillDistributed, Helm (fi-collector and fi-observed-catalog-backfill bundled in standalone)4317 gRPC, 4318 HTTP, 9464 adminnonroot (65532)GET /healthz on :9464, for the fi-collector command onlyamd64, arm6425 (measured 17.7)
futureagi/agentcc-gatewayThe LLM gatewayDistributed, Helm (binary bundled in standalone)808065532GET /healthz on :8080amd64, arm649 (measured 6.5)
futureagi/servingEmbedding and audio/image model serverStandalone (COMPOSE_PROFILES=ml), Distributed, Helm8080root (Helm runs it as appuser, 1000)GET /health on :8080amd64, arm64520 amd64, 480 arm64
futureagi/serving:*-gpuThe same with CUDA 12.4 torchany, on an NVIDIA host8080root (Helm: 1000)GET /health on :8080amd643800
futureagi/code-executornsjail sandbox for untrusted code evalsStandalone (COMPOSE_PROFILES=sandbox), Distributed, Helm; needs privileged8060rootGET /health on :8060amd64, arm64225
futureagi/future-agi-simulation-runnerTemporal worker for the simulation_runner queue: the default backend variant plus the Agent Learning Kit SDKDistributed, Helmnoneroot (from the backend)inherited from the backend: healthy while it runsamd641525, reported only
futureagi/code-executor-baseBuild input of code-executor (nsjail, Node.js, sandbox libraries); never run on its ownnoneamd64, arm64counted in code-executor

A fresh Standalone install downloads standalone, postgres:16 and clickhouse/clickhouse-server:25.3-alpine: 884 MB at most (measured 803).

Backend variants

futureagi/Dockerfile.oss builds the backend in two variants, chosen by one build argument, IMAGE_VARIANT:

Default (IMAGE_VARIANT=standard)Slim (IMAGE_VARIANT=slim)
Published asfutureagi/future-agi:vX.Y.Z (and vX.Y, latest)futureagi/future-agi:vX.Y.Z-slim (and vX.Y-slim, latest-slim)
Used byDistributed, Helm, the simulation runner, and the EE and cloud images; ./bin/install --distributed --from-source and ./bin/e2e build itThe base of futureagi/standalone, so Standalone; ./bin/install --from-source and ./bin/dev build it for Standalone
ContentsWhat earlier releases shipped: the sandbox (Daytona, E2B), billing, ops (Flower), gcp (Vertex AI SDK), langchain, rabbitmq and localizer (Claude Agent SDK) dependency groups, uv, git, Debian’s ffmpeg, every NLTK package and untrimmed site-packages. Only development tools (type stubs, the debug toolbar) moved to the dev groupBase dependencies only, no uv or git, a minimal LGPL ffmpeg build, the English NLTK data the app loads, and trimmed site-packages
SizeAbout the size of earlier releases; the budget is in Images at a glanceSee Images at a glance

Both run the same code and dependency versions (from uv.lock). What the slim variant leaves out shows up in a Standalone install as:

  • Hosted agent runs on Daytona or E2B answer 501 sandbox_sdk_missing, and runs from a GitHub source 501 git_unavailable.
  • The Vertex AI partner models (Model Garden, Gemma, Claude, Llama and Mistral on Vertex) are hidden from the model picker.
  • SERVICE_TYPE=flower and the RabbitMQ channel layer are unavailable.
  • Error localization runs its original backend (ERROR_LOCALIZER_BACKEND=legacy, which cannot localize simulation call audio) instead of the Claude Agent SDK one.
  • An audio upload in an exotic codec (AV1, WavPack, ProRes) fails with “Decoder not found”.

IMAGE_VARIANT only sets the defaults of the per-feature build arguments (Build arguments); one passed explicitly wins. A Standalone install that needs any of the above can build its app image from the default variant, from a checkout of the same tag (the image’s bootstrap runs that backend’s manage.py bootstrap_install):

docker build -t futureagi/standalone:local \
  --build-arg BACKEND_IMAGE=futureagi/future-agi:vX.Y.Z deploy/standalone

Or build a slim backend with just the pieces it needs, then the app image on top of it:

docker build -f futureagi/Dockerfile.oss --build-arg IMAGE_VARIANT=slim \
  --build-arg EXTRAS=sandbox --build-arg WITH_GIT=true -t futureagi/future-agi:local futureagi
docker build -t futureagi/standalone:local \
  --build-arg BACKEND_IMAGE=futureagi/future-agi:local deploy/standalone

Then set FUTURE_AGI_VERSION=local in .env and run docker compose up -d.

Tags

TagPoints atUse it for
vX.Y.ZOne releaseProduction; pin it, or its digest
vX.YThe newest patch release of that minor versionAutomatic patch upgrades
latestThe newest releaseTrying things out; the installers’ default
vX.Y.Z-slim, vX.Y-slim, latest-slimThe slim variant of futureagi/future-agi, same schemeBuilding your own Standalone app image; -slim exists for future-agi only
vX.Y.Z-gpu, vX.Y-gpu, latest-gpuThe CUDA build of futureagi/serving, same schemeNVIDIA hosts; -gpu exists for serving only
  • A release builds every architecture, checks it, and only then points all three tags of an image at one multi-architecture manifest (build-image-multiarch.yml), so a tag never names a half-published image.
  • A version with a suffix (v1.43.0-rc1, ad-hoc builds from the per-image release-*.yml workflows) gets that one tag; vX.Y and latest do not move.
  • futureagi/code-executor-base takes exactly one immutable tag per version (base-image-publish.yml refuses to overwrite one); code-executor pins it.
  • Tags that never reach Docker Hub: :local (./bin/install --from-source, ./bin/dev), :e2e-local (./bin/e2e), :ci (CI’s local registry).

The installers choose the tag with FUTURE_AGI_VERSION in .env (empty means latest); Distributed also reads FRONTEND_VERSION, AGENTCC_GATEWAY_VERSION, FI_COLLECTOR_VERSION, SERVING_VERSION and CODE_EXECUTOR_VERSION. See Images in the configuration reference.

Labels

Every image carries the OCI annotation labels below. version, revision and created come from the VERSION, REVISION and CREATED build arguments, which the release workflows pass and each Dockerfile declares as its last instructions, so a new value changes only the image configuration and never invalidates a cached layer. A local build without them says dev and unknown.

LabelValue
org.opencontainers.image.titlee.g. Future AGI backend
org.opencontainers.image.descriptionwhat the image runs
org.opencontainers.image.sourcehttps://github.com/future-agi/future-agi
org.opencontainers.image.urlhttps://futureagi.com
org.opencontainers.image.documentationthis page
org.opencontainers.image.vendorFuture AGI
org.opencontainers.image.licensesApache-2.0; Apache-2.0 AND LicenseRef-FutureAGI-Enterprise-1.0 for future-agi, standalone and the simulation runner, which ship futureagi/ee/ (see LICENSE-EE)
org.opencontainers.image.versionthe release, e.g. v1.43.0 (the -slim and -gpu variants have the same version)
org.opencontainers.image.revisionthe 40-character commit SHA the image was built from
org.opencontainers.image.createdbuild time, UTC, RFC 3339

Extra labels: ai.futureagi.<component>.image on standalone (the backend, frontend, fi-collector, agentcc-gateway, Temporal and MinIO images it was assembled from, with digests on a release), ai.futureagi.sdk.version and ai.futureagi.backend.image on the simulation runner, and ai.futureagi.torch-backend (cpu or cu124) on serving.

Read them without pulling the image:

docker buildx imagetools inspect futureagi/standalone:latest --format '{{json .Image}}' \
  | jq '."linux/amd64".config.Labels'

Or from a pulled image:

docker image inspect futureagi/standalone:latest --format '{{json .Config.Labels}}' | jq

Verifying an image

Pin the digest

docker buildx imagetools inspect futureagi/standalone:v1.43.0 prints the manifest digest. To make Compose pull exactly those bytes, name it in a docker-compose.override.yml next to docker-compose.yml:

services:
  app:
    image: futureagi/standalone:v1.43.0@sha256:<digest>

Every release run lists, in its summary, the digest of each multi-architecture image it published. On Distributed, list the override in COMPOSE_FILE in .env: see Move to managed data stores.

Trace it to the source

The org.opencontainers.image.revision label is the commit: https://github.com/future-agi/future-agi/commit/<revision>. Before it moves any tag, the release checks that each multi-architecture image carries all the labels and the version and commit it was built from.

Signatures: not yet for the images

The images are not signed today (no cosign or Docker Content Trust signatures are published), so the first two steps are the check. Signing is planned in the release workflow (keyless cosign from GitHub Actions); once it ships, this section will give the cosign verify command and the expected certificate identity. On Kubernetes, the signed Helm chart already pins each image by digest: see Verify the chart.

Health checks

Each long-running image declares a Docker HEALTHCHECK, which docker ps shows and docker compose up --wait waits for. Kubernetes ignores it: point the pod probes at the same endpoints.

ImageProbeInterval / timeout / start period / retries
standaloneGET :8000/health/, :9464/healthz, :8080/healthz, :3000/, :9005/minio/health/live (the compose app healthcheck)15 s / 10 s / 3600 s / 5
future-agidocker/healthcheck.py: GET :80/health/ when SERVICE_TYPE=backend serves HTTP, else TCP to gRPC :50051; flower TCP :5555; workers, beat, bootstrap jobs and containers started with their own command report healthy30 s / 10 s / 600 s / 3
frontendGET :80/ (busybox wget)30 s / 5 s / 10 s / 3
fi-collectorGET :9464/healthz, only when PID 1 is fi-collector (the consumer and backfill commands of the image serve no admin port)30 s / 10 s / 30 s / 3
agentcc-gatewayGET :8080/healthz30 s / 10 s / 15 s / 3
servingGET :8080/health; models load on first use, not at start30 s / 10 s / 120 s / 5
code-executorGET :8060/health30 s / 10 s / 20 s / 3
simulation runnerInherited from future-agi
  • The backend’s /health/ answers 503 while an embedded Temporal worker is down (tfc/asgi.py), so the probe covers the worker too. The probe sends the first non-wildcard ALLOWED_HOSTS entry as its Host header, so tightening ALLOWED_HOSTS does not fail it.
  • fi-collector and agentcc-gateway have no shell, so they ship a 1.8 MB static probe, /usr/local/bin/healthcheck (its source is in both Dockerfiles).
  • HEALTHCHECK_URL (a URL, or for the backend a comma-separated list) moves the probe of future-agi, fi-collector and agentcc-gateway, for example when the gateway listens on another port. Set it in that service’s environment:, not in .env, which several services read.
  • No probe goes through HTTP_PROXY or HTTPS_PROXY.

Kubernetes probe targets:

ImageProbe
future-agiGET /health/ port 80
frontendGET / port 80
fi-collectorGET /healthz port 9464
agentcc-gatewayGET /healthz port 8080
servingGET /health port 8080
code-executorGET /health port 8060

Users

ImageUserWhy
fi-collectornonroot (65532)
agentcc-gateway65532
servingrootAn exception: existing deployments mount a root-owned model-cache volume (HF_HOME) without an fsGroup, which uid 1000 could not write. The image is ready for appuser (1000), and the Helm chart runs it that way with fsGroup: 1000 and the caches on its /models volume. NUMBA_CACHE_DIR=/tmp/numba-cache, so an arbitrary Kubernetes runAsUser also starts. Model downloads go to $HOME/.cache unless HF_HOME, SENTENCE_TRANSFORMERS_HOME and TORCH_HOME say otherwise: mount a volume at /root/.cache (or /home/appuser/.cache with user: "1000:1000") to keep them
standalonerootsupervisord starts Redis, MinIO, nginx and the API, runs code evals as the unprivileged sandbox user (uid 18060), and keeps secrets in a root-only directory
code-executorrootnsjail needs root and privileged: true to create each jail’s namespaces and cgroups; evaluated code runs inside the jail as uid 0 with every capability dropped, a read-only root and no seccomp filter
frontendroot masterThe nginx master binds :80 and writes config.js at start; the workers that serve requests run as nginx (101), as in the upstream nginx image
future-agi (both variants), simulation runnerrootThe deployments that run this image today bind :80 and mount root-owned volumes (/app/backend/logs). The image is ready to run as 1000:1000: see below

To run the backend as a non-root user: /app/backend, its logs, media and static directories, and the directories the app writes under /app/backend/tfc (logs, which the settings create on import, metadata and saml_logs for SAML, compare for dataset comparisons) belong to appuser (1000), so:

  • Compose: add user: "1000:1000" to the backend services (docker-compose.distributed.yml). Docker 20.10 and later let any user bind :80 inside a container.
  • Kubernetes: runAsUser: 1000, runAsGroup: 1000, fsGroup: 1000 (volumes such as a logs volume become writable), and the safe sysctl net.ipv4.ip_unprivileged_port_start=0 for port 80.

Files you mount into a non-root image (the gateway’s config and Google credentials, for example) must be readable by its user: mode 0644, or a Kubernetes Secret or ConfigMap with its default mode. File sinks you configure (a disk cache or file audit log in the gateway) need a mounted directory that user can write.

Stopping

Every image stops on SIGTERM, except frontend (SIGQUIT: nginx finishes the requests in flight). Give the containers that drain work time to do it: standalone 60 s (the API drains its Temporal worker for up to 50 s), the simulation runner more than TEMPORAL_GRACEFUL_SHUTDOWN_TIMEOUT (compose sets 330 s), Temporal workers TEMPORAL_GRACEFUL_SHUTDOWN_TIMEOUT plus a margin.

Base images

Every base is set by an ARG near the top of its Dockerfile, pinned by digest, so a rebuild of the same commit reuses the same layers and an upgrade downloads only what changed.

BasePinned asUsed by
python:3.11-slim-bookwormdigestfuture-agi (so standalone and the simulation runner), serving, code-executor-base: one download for all of them
ghcr.io/astral-sh/uv:0.11.16digestBuild stages of future-agi and serving; the default future-agi variant ships its uv and uvx in /usr/local/bin
node:22.18.0digestfrontend build stage, never shipped
nginx:1.31.6-alpine-slimdigestfrontend
gcr.io/distroless/static-debian12:nonrootdigestfi-collector
scratch(empty)agentcc-gateway
temporalio/temporal:1.9.1, ghcr.io/coollabsio/miniodigestBinaries copied into standalone

Deliberately not pinned by digest, each explained in its Dockerfile:

  • golang:1.24-alpine and golang:1.26-alpine float on the minor version: build stages only, and Go patch releases carry standard-library security fixes that are compiled into the binaries.
  • standalone’s component images and the simulation runner’s backend default to :latest for a quick local build; a release passes this release’s images pinned by digest (the -slim backend to standalone, the default one to the simulation runner).
  • code-executor pins futureagi/code-executor-base by an immutable version tag; the digest is added once that version is published.

A weekly check flags a pinned tag that has moved, for example after a Debian security update, and the new digest lands in a pull request like any other change.

Build arguments

Standard, on every image:

ArgumentDefaultSet by a release to
VERSIONdevThe release tag, vX.Y.Z
REVISIONunknownThe commit SHA
CREATEDemptyThe build time, UTC

Per image:

ImageArgumentDefaultEffect
future-agiIMAGE_VARIANTstandardstandard or slim (Backend variants); sets the default of each argument below that is left empty
EXTRASstandard: sandbox,billing,ops,gcp,langchain,rabbitmq,localizer; slim: noneOptional dependency groups, comma-separated: audio, ml, voice, pii, prompt-opt, vectordb, rabbitmq, gcp, sandbox, billing, ops, langchain, localizer (pinned by uv.lock). A value replaces the variant’s list (include its groups to keep them); none installs no group
FFMPEG_FLAVORstandard: debian; slim: minimalminimal (LGPL build, about 9 MB), debian (Debian’s ffmpeg, about +145 MB), none (audio upload and video thumbnails fail)
WITH_GITstandard: true; slim: falsegit (+29 MB) for hosted-harness GitHub sources, which otherwise answer 501
WITH_UVstandard: true; slim: falseShips uv and uvx for images that install packages on top
SLIM_SITE_PACKAGESstandard: 0; slim: 11 trims site-packages (test suites, type stubs, the Google API discovery documents the app does not call)
STRIP_SOstandard: 0; slim: 1With SLIM_SITE_PACKAGES=1, 1 also strips debug sections of extension modules
NLTK_DATA_PROFILEstandard: full; slim: minimalfull bakes every NLTK package (all languages, the legacy packages and the archives); minimal the English data the app loads
PYTHON_IMAGE, UV_IMAGEpinnedBase images
servingTORCH_BACKENDcpucu124 (or another CUDA index) builds the -gpu image
frontendVITE_HOST_APIhttp://localhost:8000API URL baked into the bundle (a container overrides it at start with VITE_HOST_API)
VITE_ENVIRONMENTproduction
PRUNE_PUBLIC_ASSETSREADME and marketing imagesSet it empty to keep every public/ file
standaloneBACKEND_IMAGE, FRONTEND_IMAGE, FI_COLLECTOR_IMAGE, AGENTCC_GATEWAY_IMAGEfutureagi/<image>:latestThe component images it is assembled from
TEMPORAL_IMAGE, MINIO_IMAGEpinned
simulation runnerFI_VERSIONrequiredAgent Learning Kit SDK version (PyPI)
BACKEND_IMAGEfutureagi/future-agi:latestThe backend it extends; the build fails on one without the sandbox SDKs and git, such as a -slim tag
LIVEKIT_AGENTS_VERSION1.8.3
code-executorCODE_EXECUTOR_BASEfutureagi/code-executor-base:v1.1.0Its base; bump it whenever Dockerfile.base changes (backend-ci.yml enforces this)

Build the images yourself

From a checkout of the future-agi repository, the installers build every image and install from them:

./bin/install --from-source                 # slim backend, frontend, fi-collector, gateway, then standalone, as :local
./bin/install --distributed --from-source   # default backend, frontend, fi-collector, gateway, as :local
./bin/dev                                   # the same images, with hot reload

Or build one image at a time:

docker build -f futureagi/Dockerfile.oss -t futureagi/future-agi:local \
  --build-arg REVISION="$(git rev-parse HEAD)" futureagi    # add --build-arg IMAGE_VARIANT=slim for the slim variant
docker build -t futureagi/frontend:local frontend
docker build -t futureagi/fi-collector:local fi-collector
docker build -t futureagi/agentcc-gateway:local agentcc-gateway
docker build -f futureagi/model_serving/Dockerfile.oss -t futureagi/serving:local futureagi/model_serving
docker build -f futureagi/code-executor/Dockerfile.base -t futureagi/code-executor-base:v1.1.0 futureagi/code-executor
docker build -t futureagi/code-executor:local futureagi/code-executor

./bin/dev and the development workflow are covered in Local development.

Dive deeper

Was this page helpful?

Questions & Discussion