Skip to content

floci-io/floci

v1.0.0MIT

Run, wire up and troubleshoot Floci, the free local emulators for AWS, GCP, Azure and OCI: floci-cli lifecycle, safe wiring of aws, gcloud, az, oci and the SDKs, docker run and Docker Compose files, several instances side by side, and lookups in the published docs.


What is this?

floci-cli is the official command-line interface for Floci, the free, open-source local cloud emulators. It starts, stops, configures and diagnoses the emulator containers, and prints the environment your cloud CLI or SDK needs to talk to them. It does not manage cloud resources itself; your usual aws, gcloud, az and oci tools do that against the emulator (see Scope).

# AWS (default)
floci start
eval $(floci env)
aws s3 mb s3://my-bucket

# GCP
floci gcp start
eval $(floci gcp env)
gcloud storage buckets create gs://my-bucket

# Azure
floci az start
floci az setup
eval $(floci az env)
az storage container create --name mycontainer
az group create -n my-rg -l westeurope

# OCI
floci oci start
floci oci setup
eval $(floci oci env)
oci os ns get

The Floci emulators

floci-cli drives every member of the Floci emulator family. Floci is named after floccus, the cloud formation that looks like popcorn.

EmulatorCloudPortCLI tree
flociAWS4566floci / floci aws (default)
floci-azAzure4577floci az
floci-gcpGCP4588floci gcp
floci-ociOCI4599floci oci

Installation

Homebrew (macOS / Linux)

brew install floci-io/floci/floci

Install script (Linux / macOS)

curl -fsSL https://floci.io/install.sh | sh

Windows (PowerShell)

iwr https://floci.io/install.ps1 | iex

JVM fallback

Download floci.jar from the latest release and run it (requires Java 25+):

java -jar floci.jar version

Staying up to date

Native-binary installs (install script, direct download) can self-update:

floci update --check   # exit 0: up to date, 1: update available, 2: the check failed
floci update           # download, verify checksum, replace the binary

Homebrew installs are updated through Homebrew (brew upgrade floci); floci update detects Homebrew-managed binaries and refuses to touch them.


Quick Start

AWS

# Start Floci (AWS emulator)
floci start

# Check environment
floci doctor

# Export AWS environment variables
eval $(floci env)

# Use AWS services normally
aws s3 mb s3://my-bucket
aws dynamodb create-table --table-name users \
  --attribute-definitions AttributeName=id,AttributeType=S \
  --key-schema AttributeName=id,KeyType=HASH \
  --billing-mode PAY_PER_REQUEST

# Stop Floci
floci stop

GCP

# Start Floci GCP emulator
floci gcp start

# Check environment
floci gcp doctor

# Export GCP emulator host variables
eval $(floci gcp env)

# Use GCP services normally
gcloud storage buckets create gs://my-bucket
gcloud pubsub topics create my-topic

# Stop Floci GCP
floci gcp stop

Azure

# Start Floci Azure emulator
floci az start

# Check environment
floci az doctor

# Point the az CLI at the emulator (certificate, cloud, login)
floci az setup

# Export the connection string and the az CLI config
eval $(floci az env)

# Use Azure services
az storage container create --name mycontainer
az storage blob upload --container-name mycontainer --name hello.txt --data "hello"
az group create -n my-rg -l westeurope

# Stop Floci Azure
floci az stop

OCI

# Start Floci OCI emulator
floci oci start

# Check environment
floci oci doctor

# One-time: create a throwaway OCI CLI profile (API key + ~/.oci/config)
floci oci setup

# Export OCI endpoint variables
eval $(floci oci env)

# Use OCI services normally
oci os ns get
oci os bucket create --namespace-name floci-local --name my-bucket \
  --compartment-id ocid1.tenancy.oc1..flocilocaltenancy0000000000000000000000000000000000000000

# Stop Floci OCI
floci oci stop

Switch default product

Bare commands like floci start route to the configured default product (AWS by default).

floci config default-product gcp  # make floci gcp the default
floci config default-product az   # make floci az the default
floci config default-product oci  # make floci oci the default
floci config default-product aws  # revert to aws

Command Reference

Commands are organized into four product groups: floci aws (or bare floci), floci gcp, floci az, and floci oci. All groups expose the same lifecycle commands.

Shared commands (product-independent)

CommandDescription
floci config default-productSet the default product (aws, gcp, az, or oci)
floci updateSelf-update the CLI to the latest release
floci completion bash|zshGenerate shell completion scripts

AWS commands (floci / floci aws)

CommandDescription
floci startLaunch the Floci AWS container
floci stopStop (and optionally remove) the container
floci restartStop then start
floci statusShow container state and server health
floci logsStream container logs
floci waitPoll until Floci is ready (CI-friendly)
floci versionShow CLI and server versions
floci servicesList enabled AWS services
floci resetDelete every resource in the running emulator, keeping it running
floci doctorRun environment diagnostics
floci envPrint AWS environment variables
floci snapshot save/load/list/deleteManage state snapshots
floci config show|validate|profileShow the active configuration, validate a docker-compose.yml, manage profiles (AWS defaults)

Bare floci config ... always means the AWS tree, whatever the default product; use floci gcp config ... and so on for the others.

GCP commands (floci gcp)

CommandDescription
floci gcp startLaunch the Floci GCP container
floci gcp stopStop (and optionally remove) the container
floci gcp restartStop then start
floci gcp statusShow container state and server health
floci gcp logsStream container logs
floci gcp waitPoll until Floci GCP is ready (CI-friendly)
floci gcp versionShow CLI and server versions
floci gcp servicesList enabled GCP services
floci gcp resetDelete every resource in the running emulator, keeping it running
floci gcp doctorRun GCP environment diagnostics
floci gcp envPrint GCP SDK emulator host variables
floci gcp snapshotSnapshot commands (coming soon)
floci gcp config show|validate|profileShow the active configuration, validate a docker-compose.yml, manage profiles (GCP defaults)

Azure commands (floci az)

CommandDescription
floci az startLaunch the Floci Azure container
floci az stopStop (and optionally remove) the container
floci az restartStop then start
floci az statusShow container state and server health
floci az logsStream container logs
floci az waitPoll until Floci Azure is ready (CI-friendly)
floci az versionShow CLI and server versions
floci az servicesList enabled Azure services
floci az resetDelete every resource in the running emulator, keeping it running
floci az doctorRun Azure environment diagnostics
floci az envPrint Azure connection string / SDK env vars
floci az setupPoint the az CLI at the emulator: trust its certificate, register the cloud, log in
floci az snapshotSnapshot commands (coming soon)
floci az config show|validate|profileShow the active configuration, validate a docker-compose.yml, manage profiles (Azure defaults)

OCI commands (floci oci)

CommandDescription
floci oci startLaunch the Floci OCI container
floci oci stopStop (and optionally remove) the container
floci oci restartStop then start
floci oci statusShow container state and server health
floci oci logsStream container logs
floci oci waitPoll until Floci OCI is ready (CI-friendly)
floci oci versionShow CLI and server versions
floci oci servicesList enabled OCI services
floci oci resetDelete every resource in the running emulator, keeping it running
floci oci doctorRun OCI environment diagnostics
floci oci envPrint OCI endpoint variables
floci oci setupCreate a local OCI CLI profile (API key + ~/.oci/config)
floci oci snapshotSnapshot commands (coming soon)
floci oci config show|validate|profileShow the active configuration, validate a docker-compose.yml, manage profiles (OCI defaults)

All commands support --help.


Global Flags

Every tree takes the same flags; only the defaults differ. With --json (or -o json, -o yaml) a command prints one document on stdout and nothing else. When a command cannot do what it was asked, the error is on stderr and stdout is empty. Exit 1 does not always mean that, though: doctor, status and config validate answer a question, and start and restart report on a container they did create, so each still prints its document when the answer is "no" (a failed check, an instance that is down, a file with errors, a start that never became ready). wait prints nothing when it times out. Read the exit code first, then the document.

Two commands print text whatever the format, because their output is not a document: logs (the container's own output) and completion (a script). env prints shell code in text mode and the variables as a map in JSON or YAML. Marks are plain ASCII without --no-emoji too whenever the output is not a terminal (a pipe, a file, CI logs) or NO_COLOR is set. --json wins when it is combined with --output.

AWS global flags

--endpoint <url>            Floci server URL     (default: http://localhost:4566, env: FLOCI_ENDPOINT)
--container <name>          Container name       (default: floci, env: FLOCI_CONTAINER)
--output|-o text|json|yaml  Output format        (default: text)
--json                      Shorthand for --output json
--quiet, -q                 Suppress non-error output
--verbose, -v               Debug logging to stderr
--no-color                  Disable ANSI colors
--no-emoji                  Plain ASCII marks (+ ! x ->) instead of Unicode ones
--profile <name>            Load settings from ~/.floci/profiles/<name>.yaml

Explicit flags override the profile; the profile overrides the environment variables.

GCP global flags

--endpoint <url>            Floci GCP server URL    (default: http://localhost:4588, env: FLOCI_GCP_ENDPOINT)
--container <name>          Container name          (default: floci-gcp, env: FLOCI_GCP_CONTAINER)
--output|-o text|json|yaml  Output format           (default: text)
--json                      Shorthand for --output json
--quiet, -q                 Suppress non-error output
--verbose, -v               Debug logging to stderr
--no-color                  Disable ANSI colors
--no-emoji                  Plain ASCII marks (+ ! x ->) instead of Unicode ones
--profile <name>            Load settings from ~/.floci/profiles/<name>.yaml

Explicit flags override the profile; the profile overrides the environment variables.

Azure global flags

--endpoint <url>            Floci Azure server URL  (default: http://localhost:4577, env: FLOCI_AZ_ENDPOINT)
--container <name>          Container name          (default: floci-az, env: FLOCI_AZ_CONTAINER)
--output|-o text|json|yaml  Output format           (default: text)
--json                      Shorthand for --output json
--quiet, -q                 Suppress non-error output
--verbose, -v               Debug logging to stderr
--no-color                  Disable ANSI colors
--no-emoji                  Plain ASCII marks (+ ! x ->) instead of Unicode ones
--profile <name>            Load settings from ~/.floci/profiles/<name>.yaml

Explicit flags override the profile; the profile overrides the environment variables.

OCI global flags

--endpoint <url>            Floci OCI server URL    (default: http://localhost:4599, env: FLOCI_OCI_ENDPOINT)
--container <name>          Container name          (default: floci-oci, env: FLOCI_OCI_CONTAINER)
--output|-o text|json|yaml  Output format           (default: text)
--json                      Shorthand for --output json
--quiet, -q                 Suppress non-error output
--verbose, -v               Debug logging to stderr
--no-color                  Disable ANSI colors
--no-emoji                  Plain ASCII marks (+ ! x ->) instead of Unicode ones
--profile <name>            Load settings from ~/.floci/profiles/<name>.yaml

Explicit flags override the profile; the profile overrides the environment variables.

Port auto-detection: status, version, wait, and env automatically derive the correct endpoint from the container's port mapping. You don't need to pass --endpoint when using a non-default port, as long as --container points to the right container.


Commands

floci start / floci gcp start / floci az start / floci oci start

Pulls the image (if needed), starts the container, and waits for readiness.

# AWS
floci start                          # default port 4566
floci start --port 4567              # custom host port
floci start --services s3,dynamodb   # enable specific services
floci start --persist ./data         # persist state to a host directory
floci start --pull always            # always pull the latest image
floci start --detach                 # return immediately, don't wait
floci start --namespace team-b       # scope the containers it launches (see below)

# GCP
floci gcp start                      # default port 4588
floci gcp start --persist ./data     # persist state to a host directory
floci gcp start --namespace team-b   # scope the containers it launches

# Azure
floci az start                       # default port 4577
floci az start --port 4578           # custom host port
floci az start --persist ./data      # persist state to a host directory
floci az start --namespace team-b    # scope the containers it launches

# OCI
floci oci start                      # default port 4599
floci oci start --persist ./data     # persist state to a host directory
floci oci start --namespace team-b   # scope the containers it launches

--namespace sets the emulator's Docker resource namespace (FLOCI_DOCKER_RESOURCE_NAMESPACE, FLOCI_GCP_…, FLOCI_AZ_…, FLOCI_OCI_…). The emulator puts it in the names and the floci_namespace label of the containers and volumes it launches (Lambda, ECS, RDS, Cloud Run, Service Bus, ...) and only cleans up leftovers in its own namespace. When --container is not the product default, the namespace is derived from it, without the default-container prefix the emulator already adds (floci-gcp-b → b, so children are floci-gcp-b-…; team-b stays team-b). The default container gets none.

On a --port other than the product default, start also sets the emulator's base URL (FLOCI_BASE_URL, FLOCI_GCP_BASE_URL, ...) to the endpoint with that port (http://localhost:<port> unless --endpoint names another host), so URLs it returns (SQS QueueUrl, presigned URLs, the OCI functions invoke endpoint) point at that instance.

Docker daemon resolution (Podman, rootless, remote contexts)

The Floci container needs access to a Docker-compatible daemon (for Lambda, EC2, EKS, MSK, ECR, CodeBuild, and Kafka/Redpanda support). By default floci start bind-mounts /var/run/docker.sock, but it honors the standard DOCKER_HOST environment variable, so Podman, rootless setups, and remote Docker contexts work without extra flags:

# Rootless Podman
export DOCKER_HOST=unix:///run/user/1000/podman/podman.sock
floci start

# Rootful Podman
export DOCKER_HOST=unix:///run/podman/podman.sock
floci start

# Remote daemon over TCP
export DOCKER_HOST=tcp://10.0.0.5:2375
floci start

Resolution precedence:

  1. DOCKER_HOST: the standard Docker/Podman variable (unix:// socket, tcp:// daemon, or npipe:// on Windows)
  2. DOCKER_SOCK: legacy override (a bare socket path)
  3. OS default: /var/run/docker.sock on Linux/macOS, or the Docker named pipe on Windows

For a unix:// socket the resolved path is bind-mounted into the container; for a remote tcp:// daemon the DOCKER_HOST value is passed through to the container instead. Run floci doctor to see which endpoint was resolved.

floci stop / floci gcp stop / floci az stop / floci oci stop

floci stop                    # graceful stop (10s timeout)
floci stop --timeout 30       # wait up to 30s before force-kill
floci stop --timeout -1       # never force-kill: wait for the container to exit
floci stop --remove           # also remove the container after stopping
floci stop -o json            # {"container", "state", "stopped", "removed"}

start, stop and restart print one document with -o json or -o yaml and nothing else on stdout: the progress lines are left out and docker's pull progress goes to stderr. start and restart report container, id, image, endpoint, state and ready (ready is absent with --detach). logs prints the container's own output and stays plain text.

floci status / floci gcp status / floci az status / floci oci status

floci status                          # auto-detects endpoint from container port mapping
floci status --container myfloci      # target a specific container
floci status -o json                  # structured output
floci status >/dev/null && echo up    # exit 0: the instance is up, exit 1: it is not

status exits 0 when the server answers and its container, if there is one, is running, and 1 otherwise, in every output format. An instance with no local container (a remote --endpoint, a Compose service under another name) counts as up when it answers.

floci env

Prints AWS environment variables pointing at the running Floci instance. The default hostname is localhost.floci.io (resolves to 127.0.0.1, enables virtual-hosted S3 bucket names).

eval $(floci env)                          # bash/zsh: sets all four AWS vars
floci env --shell fish | source            # fish
floci env --shell powershell | Invoke-Expression  # PowerShell

floci env --host myhost.local              # custom hostname
floci env --region eu-west-1              # custom region (default: us-east-1)
floci env -o json                          # structured output for scripts

Variables exported:

VariableDefault value
AWS_ENDPOINT_URLhttp://localhost.floci.io:<port>
AWS_ACCESS_KEY_IDtest
AWS_SECRET_ACCESS_KEYtest
AWS_DEFAULT_REGIONus-east-1

floci gcp env

Prints GCP SDK emulator host variables for the running Floci GCP instance.

eval $(floci gcp env)                        # all emulator host vars
eval $(floci gcp env --service gcs,pubsub)   # specific services only

floci gcp env --shell fish | source          # fish
floci gcp env -o json                        # structured output

Variables exported (per enabled service):

VariableService
STORAGE_EMULATOR_HOSTCloud Storage (gcs)
PUBSUB_EMULATOR_HOSTPub/Sub
FIRESTORE_EMULATOR_HOSTFirestore
DATASTORE_EMULATOR_HOSTDatastore
SECRET_MANAGER_EMULATOR_HOSTSecret Manager
IAM_EMULATOR_HOSTIAM

floci az env

Prints Azure connection variables for the running Floci Azure instance. The connection string contains ; separators, so the emitted value is single-quoted (as it is in every tree's env output) and is safe to eval.

eval $(floci az env)                                # connection string (default)
eval $(floci az env --format sdk-vars)              # individual SDK endpoint vars
eval $(floci az env --format sdk-vars --service blob,queue)  # specific services only

floci az env --shell fish | source                  # fish
floci az env -o json                                # structured output

Connection string mode (default) exports:

VariableValue
AZURE_STORAGE_CONNECTION_STRINGFull Azurite-compatible connection string

SDK vars mode (--format sdk-vars) exports:

VariableDefault value
AZURE_STORAGE_ACCOUNTdevstoreaccount1
AZURE_STORAGE_KEYAzurite dev key
AZURE_STORAGE_BLOB_ENDPOINThttp://localhost.floci.io:<port>/devstoreaccount1
AZURE_STORAGE_QUEUE_ENDPOINThttp://localhost.floci.io:<port>/devstoreaccount1-queue
AZURE_STORAGE_TABLE_ENDPOINThttp://localhost.floci.io:<port>/devstoreaccount1-table
AZURE_FUNCTIONS_ENDPOINThttp://localhost.floci.io:<port>/devstoreaccount1-functions
AZURE_APP_CONFIGURATION_ENDPOINThttp://localhost.floci.io:<port>/devstoreaccount1-appconfig
AZURE_KEY_VAULT_ENDPOINThttp://localhost.floci.io:<port>/devstoreaccount1-keyvault

After floci az setup, both modes also export:

VariableValue
AZURE_CONFIG_DIR~/.floci/az/<container>/azure-config, the instance's isolated az config; after --global it is unset instead, so a value left by another instance's eval does not linger
REQUESTS_CA_BUNDLE~/.floci/az/<container>/ca-bundle.pem, the public roots plus that instance's certificate

If the instance's certificate changed since setup (a container recreated without --persist), floci az env warns on stderr and tells you to re-run floci az setup.

floci az setup

az group create, az login and every other control-plane command go to public Azure unless the az CLI is told otherwise. floci az setup does it in one step:

  1. fetches the emulator's CA certificate from /_floci/tls-cert and writes a CA bundle (the JDK's public roots plus that certificate);
  2. registers (or updates) an az cloud named after the container (floci-az by default) whose ARM and Entra endpoints point at https://localhost:<port>, and makes it the active cloud;
  3. turns off core.instance_discovery, which otherwise fails the login with invalid_instance;
  4. logs in as a service principal with the dev identity (tenant 00000000-0000-0000-0000-000000000002, subscription 00000000-0000-0000-0000-000000000001).

Everything is kept per instance, in ~/.floci/az/<container>/, so instances started from different profiles never share a certificate, cloud or login (see Running several instances side by side). By default the az config itself is isolated there too and ~/.azure is left untouched; eval $(floci az env) then points az at it in the current shell only. --global writes to your default az config instead, and removes that instance's earlier isolated config. Re-running is safe: the cloud is updated, not registered twice.

The az CLI only logs in over HTTPS, so floci az start always starts Floci Azure with FLOCI_AZ_TLS_ENABLED=true (HTTP keeps working on the same port). A container started by an older floci has TLS off; run floci az restart once.

floci az setup                          # isolated config under ~/.floci/az/floci-az
eval $(floci az env)                    # AZURE_CONFIG_DIR + REQUESTS_CA_BUNDLE + connection string
az group create -n my-rg -l westeurope

floci az setup --profile team-b         # a second instance: ~/.floci/az/<its container>
eval $(floci az env --profile team-b)

floci az setup --global                 # use your default az config (~/.azure)
eval $(floci az env)                    # REQUESTS_CA_BUNDLE, and clears a stale AZURE_CONFIG_DIR

floci az setup --reset                  # delete the isolated config
floci az setup --reset --global         # switch the default az config back to AzureCloud
floci az setup -o json                  # structured output

Requires the az CLI on your PATH. --tenant, --subscription, --client-id and --client-secret override the dev identity; Floci Azure never checks the secret.

floci oci env

Prints OCI endpoint variables for the running Floci OCI instance. OCI SDKs and the oci CLI take a single endpoint for every service, so no per-service variables are needed.

eval $(floci oci env)                        # endpoint vars for CLI, wrappers, and Terraform

floci oci env --shell fish | source          # fish
floci oci env -o json                        # structured output

Variables exported:

VariablePurpose
OCI_CLI_ENDPOINTDefault --endpoint for the oci CLI
FLOCI_OCI_ENDPOINTUsed by this CLI and the ocilocal wrapper
TF_VAR_CLIENT_HOST_OVERRIDESPer-client host overrides for the oracle/oci Terraform provider
OCI_CLI_PROFILEThe profile floci oci setup wrote (default FLOCI); only exported when detected in ~/.oci/config, and skipped for DEFAULT

floci oci setup

The OCI CLI and SDKs refuse to run without a config file and an API signing key, even against an emulator that never validates them. floci oci setup creates both in one step: a locally generated RSA-2048 key at ~/.oci/floci_key.pem and a [FLOCI] profile in ~/.oci/config with the emulator's canonical throwaway tenancy. Existing profiles are never touched; re-running is a no-op.

floci oci setup                        # create key + [FLOCI] profile
floci oci setup --profile-name DEFAULT # write a different profile section
floci oci setup -o json                # structured output

# then connect:
eval $(floci oci env)                  # exports OCI_CLI_PROFILE=FLOCI too
oci os ns get

floci logs / floci gcp logs / floci az logs / floci oci logs

floci logs                       # last logs from the container
floci logs --tail 50             # last 50 lines
floci logs --since 5m            # logs from the last 5 minutes
floci logs --follow              # stream live logs (Ctrl-C to stop)

floci wait / floci gcp wait / floci az wait / floci oci wait

floci wait                        # wait up to 30s (default)
floci wait --timeout 2m           # custom timeout (supports s, m, h)
floci wait --service dynamodb     # wait until a specific service is ready
floci wait -o json                # machine-readable output

floci doctor / floci gcp doctor / floci az doctor / floci oci doctor

floci doctor                      # run all checks
floci doctor --check docker.installed   # run a single check by name
floci doctor -o json              # structured output for scripts

floci gcp doctor                  # GCP-specific checks
floci az doctor                   # Azure-specific checks (includes az CLI + connection string)
floci oci doctor                  # OCI-specific checks

floci version / floci gcp version / floci az version / floci oci version

floci version                     # CLI version, server version, image digest
floci version -o json

floci version and floci status warn on stderr when the AWS server is older than 1.5.0, the oldest version this CLI supports. The GCP, Azure and OCI emulators are versioned separately and have no minimum yet.

floci services / floci gcp services / floci az services / floci oci services

floci services                    # list all enabled services
floci services -o json

floci reset / floci gcp reset / floci az reset / floci oci reset

floci reset                       # asks first, then deletes every resource; the emulator keeps running
floci reset --yes                 # no prompt (required when not on a terminal, e.g. in CI)
floci gcp reset -y -o json

It calls the emulator's POST <prefix>/state/reset. The AWS, GCP and OCI emulators serve it; on a server without it (currently floci-az) the command says reset is not available and exits 1. Without --yes and with no terminal to ask on, it exits 2.

Reset never guesses which server to wipe:

  • An --endpoint you type is used as given.
  • A container you select (--container, a profile's container, or FLOCI_CONTAINER) has to be running. If it is missing or stopped, nothing is reset.
  • An endpoint a profile or FLOCI_ENDPOINT supplies is used when no container is selected. A container that happens to run locally under the default name never takes its place.
  • When both a container and an endpoint are configured, they have to be the same server. If they are not, nothing is reset and you are asked to pass --endpoint or --container.
  • A container on a remote Docker host (DOCKER_HOST=tcp://other-host:... or ssh://...) is only reset through an endpoint, since its published port is not on this machine. A daemon on this machine reached over TCP (tcp://127.0.0.1:2375) is local.

When reset refuses to choose a server, the command exits 1 without sending anything.

floci config

floci config show                          # show active configuration
floci config default-product aws|gcp|az|oci  # set the default product (persisted to ~/.floci/config.yaml)
floci config profile list                  # list saved profiles: container, port, data dir
floci config profile create <name>         # create a new profile with the tree's defaults
floci config profile create <name> --container <c> --port <p> --persist <dir> --services <csv> --image <img> --namespace <ns>
floci config profile show <name>           # show a profile
floci config profile show <name> --json    # the same keys as one row of `config profile list --json`
floci config profile edit <name>           # open the profile in $VISUAL or $EDITOR, then check it still reads
floci config profile delete <name>         # delete a profile
floci config validate -f docker-compose.yml  # validate a Compose file

Each product tree has its own config show|validate|profile (floci gcp config show, ...), which uses that product's defaults; config default-product is available through bare floci config and floci aws config, but not through the GCP, Azure, or OCI config trees.

config validate reads the Compose file and checks the service that runs the emulator (found by its image; a file with a single service is checked whatever its image is):

CheckResult when it fails
The emulator port is mapped over TCP ("4566:4566", "5566:4566", "127.0.0.1:5566:4566", a range, or the long form; any host port works)error
A socket is mounted at /var/run/docker.sock in the container (the host side may be any socket)error where the product needs it, otherwise a warning
The volume at /app/data is writable and not bound to a fileerror
A volume at /app/data comes with <PREFIX>_STORAGE_MODE=persistent, and the other way roundwarning
The image tag is not older than the oldest version this CLI supports (AWS tree)warning

It exits 1 when there is an error and 0 otherwise. -o json and -o yaml print file, service, valid, errors and warnings, also for a file that cannot be parsed. An env_file is not read, so nothing is said about a storage mode it may set.

Profiles

Profiles are stored in ~/.floci/profiles/<name>.yaml. Pass --profile <name> to any command to load one; floci config profile create <name> writes a starter file seeded with the defaults of the tree you run it under.

name: probe
endpoint: http://localhost:4566
container: floci-probe
image: floci/floci:enforced
port: 4599
persistDir: /tmp/floci-persist
services: s3,lambda
namespace: team-probe
output: json

Each field supplies the default for one flag, so a profile field only affects the commands that have that flag:

Profile fieldFlag it suppliesUsed by
endpoint--endpointevery command except update and the group commands (floci gcp, floci config, ...)
container--containerevery command except update and the group commands (floci gcp, floci config, ...)
output--output / -oevery command except update and the group commands (floci gcp, floci config, ...)
image--imagestart; restart re-applies it through the start it runs
port--portstart; restart re-applies it through the start it runs
persistDir--persiststart; restart re-applies it through the start it runs
services--servicesstart; restart re-applies it through the start it runs
namespace--namespacestart; restart re-applies it through the start it runs

Resolution order, highest first:

command-line flag  >  --profile <name>  >  FLOCI_* environment variable  >  built-in default

So floci start --profile probe --container other starts other, and a profile beats a FLOCI_CONTAINER exported in your shell. A field the profile leaves out changes nothing.

An unknown or unreadable profile is an error (exit 2), not a silent fall back to the defaults. That includes floci config show --profile <name>, which before 0.2.2 warned and showed the defaults instead. A key floci does not read (a typo such as persist_dir:) is ignored with a warning that lists the keys a profile can set. Values are interpolated by the CLI, so persistDir: ${env:HOME}/floci-data expands as you would expect.

Profiles are shared by all four product trees: there is one ~/.floci/profiles/ directory, not one per product. A profile created under floci gcp carries GCP defaults, so passing it to the AWS tree will start a GCP container; name them accordingly.

floci restart --profile <name> re-applies the profile's persistDir, so state survives the restart. A plain floci restart has no --persist flag of its own and still falls back to the defaults.

Running several instances side by side

An instance is a profile. Its container name is its identity, its port is the only thing that must differ from the other instances, and its persist dir keeps its state across container recreation. Every command (status, logs, env, doctor, stop, ...) finds the instance through its container, so passing the same --profile is all it takes. Any local state the CLI keeps about an instance lives in ~/.floci/<product>/<container>/.

Each instance's emulator also gets its own Docker resource namespace, derived from the container name unless the profile sets namespace. That keeps the containers each instance launches (Lambda functions, ECS tasks, Cloud Run jobs, Service Bus sidecars, ...) apart, so starting one instance never cleans up another's. floci config show --profile <name> prints the namespace it will use.

Leave endpoint at the product default: the CLI reads the real host port from the running container. config profile create warns when a new profile reuses another profile's container, or its port or resource namespace on the same image.

# AWS
floci config profile create aws-a --container floci-a --port 4566  --persist ~/.floci/data/aws-a
floci config profile create aws-b --container floci-b --port 14566 --persist ~/.floci/data/aws-b
floci start --profile aws-a && floci start --profile aws-b
eval $(floci env --profile aws-b)          # AWS_ENDPOINT_URL points at :14566

# GCP
floci gcp config profile create gcp-b --container floci-gcp-b --port 14588 --persist ~/.floci/data/gcp-b
floci gcp start --profile gcp-b
eval $(floci gcp env --profile gcp-b)

# Azure: setup is per instance too (its own certificate, az cloud and login)
floci az config profile create az-b --container floci-az-b --port 14577 --persist ~/.floci/data/az-b
floci az start --profile az-b
floci az setup --profile az-b
eval $(floci az env --profile az-b)        # plain az now talks to floci-az-b only

# OCI: 'floci oci setup' is shared, the endpoint is per instance
floci oci config profile create oci-b --container floci-oci-b --port 14599 --persist ~/.floci/data/oci-b
floci oci start --profile oci-b
eval $(floci oci env --profile oci-b)

floci config profile list                  # one row per instance
floci stop --profile aws-b                 # stop one, the others keep running

Without --persist an instance starts empty each time its container is recreated. For floci-az it also gets a new certificate, which floci az env reports so you can re-run floci az setup.

floci snapshot

Save and restore named snapshots of Floci AWS state.

floci snapshot list
floci snapshot save <name>
floci snapshot load <name>
floci snapshot delete <name>
floci snapshot export <name> -f tarball.tar.gz
floci snapshot import tarball.tar.gz

GCP, Azure, and OCI snapshots (floci gcp snapshot / floci az snapshot / floci oci snapshot) require server-side endpoints not yet implemented in Floci GCP / Floci Azure / Floci OCI. Until then, those commands report the missing API and exit 1. floci snapshot export|import (AWS) are also pending server support and exit 1.

floci completion

floci completion bash >> ~/.bashrc
floci completion zsh  >> ~/.zshrc

Completion scripts are generated for bash and zsh. Any other shell name is a usage error (exit 2).

floci update

Self-update the CLI in place: downloads the release binary from GitHub, verifies its sha256 against the release's sha256sums.txt, and atomically replaces the running binary.

floci update                      # update to the latest release
floci update --check              # exit 0: up to date, 1: update available, 2: the check failed
floci update --version 0.1.7      # install a specific version
floci update --check || floci update   # script-friendly: update only when stale

Homebrew installs are managed by brew and are detected and refused; use brew upgrade floci there instead.

When run from an interactive terminal, floci also checks for new releases in the background (at most once per 24h, cached in ~/.floci/update-check.json) and prints a hint before the command output when one is available. Set FLOCI_NO_UPDATE_CHECK=1 to opt out; the check is automatically disabled in CI and for piped output.


Exit Codes

Every command in every tree (floci, floci aws, floci gcp, floci az, floci oci) follows the same three codes:

CodeMeaning
0The command did what it was asked.
1It ran and failed, or the answer to the question it asks is "no".
2The command line could not be used: an unknown flag or command, a missing argument, a value picocli cannot convert (--port abc), or a --profile that does not exist or cannot be read.

A value the command line accepts but the command then rejects is exit 2 as well, in every command: an out-of-range --port, an unknown --pull policy, a --persist path that cannot be used, a --version that is not a release version, an unknown product or action, a missing or invalid name. Exit 1 always means the command ran.

Where a command's codes carry a specific meaning a script can rely on:

Command012
statusthe instance is upit is not: the server does not answer, or its container is stoppedbad flag or profile
waitready before --timeouttimed out--timeout is not a positive duration
doctorevery check passed (warnings allowed)at least one check failed--check names no known check
update --checkup to datean update is availablethe check itself failed
updateupdated, or already up to datethe update failed; the binary is unchanged--version is not a release version
start, restartstarted (and ready, unless --detach)Docker, the image, the port or readiness failed, or the --persist directory cannot be created--port, --pull, the namespace or the --persist path is not valid
stopstopped, or was not runningno such container, or Docker failedbad flag or profile
resetstate resetdeclined, not available on this server, no running instance to reset, or the configuration names two different serversno terminal to ask on and no --yes
config validateno errors (warnings allowed)errors found, or the file cannot be readbad flag
config profile ...donenot found, already exists, cannot be read, or (for edit) no editor is set, the editor failed or the file no longer parsesunknown action, missing or invalid profile name, --port out of range
config default-productsavedthe file cannot be writtennot aws, gcp, az or oci
envvariables printed--shell is not supported
completionscript printedthe shell is not bash or zsh
snapshot ...donefailed, or the server has no snapshot API yetinvalid snapshot name

docs/help/ holds the --help text of every command, generated from the code. A test fails when the files and the commands drift apart; regenerate them with mvn test -Dtest=HelpSnapshotTest -Dfloci.help.update=true.


CI Usage

AWS CI

floci start --detach
floci wait --timeout 60s
eval $(floci env)
pytest  # or your test command
floci stop --remove

With Docker Compose:

services:
  floci:
    image: floci/floci:latest
    ports:
      - "4566:4566"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

Using Podman or a non-default daemon? Swap the host side of the socket mount for your daemon's socket (e.g. /run/user/1000/podman/podman.sock:/var/run/docker.sock). With the CLI, setting DOCKER_HOST is enough; see Docker daemon resolution.

GCP CI

floci gcp start --detach
floci gcp wait --timeout 60s
eval $(floci gcp env)
pytest  # or your test command
floci gcp stop --remove

With Docker Compose:

services:
  floci-gcp:
    image: floci/floci-gcp:latest
    ports:
      - "4588:4588"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

Azure CI

floci az start --detach
floci az wait --timeout 60s
eval $(floci az env)
pytest  # or your test command
floci az stop --remove

With Docker Compose:

services:
  floci-az:
    image: floci/floci-az:latest
    ports:
      - "4577:4577"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

OCI CI

floci oci start --detach
floci oci wait --timeout 60s
eval $(floci oci env)
pytest  # or your test command
floci oci stop --remove

With Docker Compose:

services:
  floci-oci:
    image: floci/floci-oci:latest
    ports:
      - "4599:4599"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

AI agents

skills/floci/ is an Agent Skill that teaches coding agents (Claude Code, Codex, Cursor, Kiro, Gemini CLI and others) to work with Floci: install and drive this CLI, wire aws, gcloud, az, oci and the SDKs to the emulators without touching real cloud, write docker run commands and Compose files, run several instances side by side, and look things up in the published documentation of each emulator (AWS, Azure, GCP, OCI) instead of guessing.

# Any supported agent (asks which ones to install it for)
npx skills add floci-io/floci-cli

# Claude Code, as a plugin
/plugin marketplace add floci-io/floci-cli
/plugin install floci@floci

In Kiro, install it as a power: Powers panel, Add Custom Power, Import power from GitHub, and enter https://github.com/floci-io/floci-cli. The plugin.json at the repository root is the Agent Plugins manifest Kiro reads. Kiro also loads plain Agent Skills, so copying skills/floci/ into .kiro/skills/ (or ~/.kiro/skills/) works as well.

Or copy the skills/floci/ directory into your agent's skills directory (for example ~/.claude/skills/floci/).

PartWhat it holds
SKILL.mdLifecycle, safety rules (fake credentials only, verify the endpoint, explicit product tree) and when to read what
references/One page per cloud, plus Docker and Compose, multiple instances and namespaces, CI, troubleshooting, and how to find a page in the docs
assets/compose/Compose templates for each emulator and for all four together
scripts/install-floci.sh and ensure-running.sh (bash)

The skill follows the CLI: SkillDocsTest checks every floci command it quotes against the real command tree.


Scope

floci-cli manages Floci's lifecycle, config, state, and diagnostics. It does not wrap the AWS, GCP, Azure, or OCI CLIs, or manage cloud resources directly. Use aws with AWS_ENDPOINT_URL, gcloud/SDKs with the emulator host variables, az with the appropriate connection string, or oci with OCI_CLI_ENDPOINT for resource operations.


Testcontainers

Running Floci in tests? Use the Testcontainers module for your language instead of scripting the CLI:

LanguageRepository
Javatestcontainers-floci
Node.js / TypeScripttestcontainers-floci-node
Pythontestcontainers-floci-python
Gotestcontainers-floci-go
.NETtestcontainers-floci-dotnet

Community

Privacy

The Floci CLI and the agent skill in skills/floci/ collect no data. There is no telemetry, no analytics, no account and no sign-in, and nothing you do with them is reported to the Floci project.

The only network requests they make are the ones needed to do what you asked:

RequestToWhen
Release checkapi.github.comAt most once every 24 hours from an interactive terminal, and on floci update. Turn it off with FLOCI_NO_UPDATE_CHECK=1; it is off in CI and for piped output
Binary downloadgithub.com (release assets)Only when you run floci update or the install script
Image pullYour container registry (Docker Hub by default)When docker pulls an emulator image on floci start
Name lookupDNS for localhost.floci.io, which answers 127.0.0.1When a tool uses the endpoint that floci env prints for AWS
Documentation pagesfloci.io and raw.githubusercontent.comWhen an agent using the skill looks something up

Those services see what any HTTP or DNS request shows them (such as your IP address) and apply their own privacy policies. Everything else stays on your machine: the emulators run locally, your cloud CLIs and SDKs talk to localhost, and profiles and state live under ~/.floci. The skill tells agents to use only the fake credentials the emulators accept and never to read or reuse real cloud credentials.

Questions about this: see Community.

License

MIT. See LICENSE.


Floci™ is a trademark of Hector Ventura. Code is MIT-licensed; see TRADEMARK.md for name and logo use.