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.
| Emulator | Cloud | Port | CLI tree |
|---|---|---|---|
| floci | AWS | 4566 | floci / floci aws (default) |
| floci-az | Azure | 4577 | floci az |
| floci-gcp | GCP | 4588 | floci gcp |
| floci-oci | OCI | 4599 | floci 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)
| Command | Description |
|---|---|
floci config default-product | Set the default product (aws, gcp, az, or oci) |
floci update | Self-update the CLI to the latest release |
floci completion bash|zsh | Generate shell completion scripts |
AWS commands (floci / floci aws)
| Command | Description |
|---|---|
floci start | Launch the Floci AWS container |
floci stop | Stop (and optionally remove) the container |
floci restart | Stop then start |
floci status | Show container state and server health |
floci logs | Stream container logs |
floci wait | Poll until Floci is ready (CI-friendly) |
floci version | Show CLI and server versions |
floci services | List enabled AWS services |
floci reset | Delete every resource in the running emulator, keeping it running |
floci doctor | Run environment diagnostics |
floci env | Print AWS environment variables |
floci snapshot save/load/list/delete | Manage state snapshots |
floci config show|validate|profile | Show 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)
| Command | Description |
|---|---|
floci gcp start | Launch the Floci GCP container |
floci gcp stop | Stop (and optionally remove) the container |
floci gcp restart | Stop then start |
floci gcp status | Show container state and server health |
floci gcp logs | Stream container logs |
floci gcp wait | Poll until Floci GCP is ready (CI-friendly) |
floci gcp version | Show CLI and server versions |
floci gcp services | List enabled GCP services |
floci gcp reset | Delete every resource in the running emulator, keeping it running |
floci gcp doctor | Run GCP environment diagnostics |
floci gcp env | Print GCP SDK emulator host variables |
floci gcp snapshot | Snapshot commands (coming soon) |
floci gcp config show|validate|profile | Show the active configuration, validate a docker-compose.yml, manage profiles (GCP defaults) |
Azure commands (floci az)
| Command | Description |
|---|---|
floci az start | Launch the Floci Azure container |
floci az stop | Stop (and optionally remove) the container |
floci az restart | Stop then start |
floci az status | Show container state and server health |
floci az logs | Stream container logs |
floci az wait | Poll until Floci Azure is ready (CI-friendly) |
floci az version | Show CLI and server versions |
floci az services | List enabled Azure services |
floci az reset | Delete every resource in the running emulator, keeping it running |
floci az doctor | Run Azure environment diagnostics |
floci az env | Print Azure connection string / SDK env vars |
floci az setup | Point the az CLI at the emulator: trust its certificate, register the cloud, log in |
floci az snapshot | Snapshot commands (coming soon) |
floci az config show|validate|profile | Show the active configuration, validate a docker-compose.yml, manage profiles (Azure defaults) |
OCI commands (floci oci)
| Command | Description |
|---|---|
floci oci start | Launch the Floci OCI container |
floci oci stop | Stop (and optionally remove) the container |
floci oci restart | Stop then start |
floci oci status | Show container state and server health |
floci oci logs | Stream container logs |
floci oci wait | Poll until Floci OCI is ready (CI-friendly) |
floci oci version | Show CLI and server versions |
floci oci services | List enabled OCI services |
floci oci reset | Delete every resource in the running emulator, keeping it running |
floci oci doctor | Run OCI environment diagnostics |
floci oci env | Print OCI endpoint variables |
floci oci setup | Create a local OCI CLI profile (API key + ~/.oci/config) |
floci oci snapshot | Snapshot commands (coming soon) |
floci oci config show|validate|profile | Show 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, andenvautomatically derive the correct endpoint from the container's port mapping. You don't need to pass--endpointwhen using a non-default port, as long as--containerpoints 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:
DOCKER_HOST: the standard Docker/Podman variable (unix://socket,tcp://daemon, ornpipe://on Windows)DOCKER_SOCK: legacy override (a bare socket path)- OS default:
/var/run/docker.sockon 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:
| Variable | Default value |
|---|---|
AWS_ENDPOINT_URL | http://localhost.floci.io:<port> |
AWS_ACCESS_KEY_ID | test |
AWS_SECRET_ACCESS_KEY | test |
AWS_DEFAULT_REGION | us-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):
| Variable | Service |
|---|---|
STORAGE_EMULATOR_HOST | Cloud Storage (gcs) |
PUBSUB_EMULATOR_HOST | Pub/Sub |
FIRESTORE_EMULATOR_HOST | Firestore |
DATASTORE_EMULATOR_HOST | Datastore |
SECRET_MANAGER_EMULATOR_HOST | Secret Manager |
IAM_EMULATOR_HOST | IAM |
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:
| Variable | Value |
|---|---|
AZURE_STORAGE_CONNECTION_STRING | Full Azurite-compatible connection string |
SDK vars mode (--format sdk-vars) exports:
| Variable | Default value |
|---|---|
AZURE_STORAGE_ACCOUNT | devstoreaccount1 |
AZURE_STORAGE_KEY | Azurite dev key |
AZURE_STORAGE_BLOB_ENDPOINT | http://localhost.floci.io:<port>/devstoreaccount1 |
AZURE_STORAGE_QUEUE_ENDPOINT | http://localhost.floci.io:<port>/devstoreaccount1-queue |
AZURE_STORAGE_TABLE_ENDPOINT | http://localhost.floci.io:<port>/devstoreaccount1-table |
AZURE_FUNCTIONS_ENDPOINT | http://localhost.floci.io:<port>/devstoreaccount1-functions |
AZURE_APP_CONFIGURATION_ENDPOINT | http://localhost.floci.io:<port>/devstoreaccount1-appconfig |
AZURE_KEY_VAULT_ENDPOINT | http://localhost.floci.io:<port>/devstoreaccount1-keyvault |
After floci az setup, both modes also export:
| Variable | Value |
|---|---|
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:
- fetches the emulator's CA certificate from
/_floci/tls-certand writes a CA bundle (the JDK's public roots plus that certificate); - registers (or updates) an az cloud named after the container (
floci-azby default) whose ARM and Entra endpoints point athttps://localhost:<port>, and makes it the active cloud; - turns off
core.instance_discovery, which otherwise fails the login withinvalid_instance; - logs in as a service principal with the dev identity (tenant
00000000-0000-0000-0000-000000000002, subscription00000000-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:
| Variable | Purpose |
|---|---|
OCI_CLI_ENDPOINT | Default --endpoint for the oci CLI |
FLOCI_OCI_ENDPOINT | Used by this CLI and the ocilocal wrapper |
TF_VAR_CLIENT_HOST_OVERRIDES | Per-client host overrides for the oracle/oci Terraform provider |
OCI_CLI_PROFILE | The 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
--endpointyou type is used as given. - A container you select (
--container, a profile'scontainer, orFLOCI_CONTAINER) has to be running. If it is missing or stopped, nothing is reset. - An endpoint a profile or
FLOCI_ENDPOINTsupplies 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
--endpointor--container. - A container on a remote Docker host (
DOCKER_HOST=tcp://other-host:...orssh://...) 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):
| Check | Result 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 file | error |
A volume at /app/data comes with <PREFIX>_STORAGE_MODE=persistent, and the other way round | warning |
| 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 field | Flag it supplies | Used by |
|---|---|---|
endpoint | --endpoint | every command except update and the group commands (floci gcp, floci config, ...) |
container | --container | every command except update and the group commands (floci gcp, floci config, ...) |
output | --output / -o | every command except update and the group commands (floci gcp, floci config, ...) |
image | --image | start; restart re-applies it through the start it runs |
port | --port | start; restart re-applies it through the start it runs |
persistDir | --persist | start; restart re-applies it through the start it runs |
services | --services | start; restart re-applies it through the start it runs |
namespace | --namespace | start; 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 underfloci gcpcarries 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'spersistDir, so state survives the restart. A plainfloci restarthas no--persistflag 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:
| Code | Meaning |
|---|---|
0 | The command did what it was asked. |
1 | It ran and failed, or the answer to the question it asks is "no". |
2 | The 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:
| Command | 0 | 1 | 2 |
|---|---|---|---|
status | the instance is up | it is not: the server does not answer, or its container is stopped | bad flag or profile |
wait | ready before --timeout | timed out | --timeout is not a positive duration |
doctor | every check passed (warnings allowed) | at least one check failed | --check names no known check |
update --check | up to date | an update is available | the check itself failed |
update | updated, or already up to date | the update failed; the binary is unchanged | --version is not a release version |
start, restart | started (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 |
stop | stopped, or was not running | no such container, or Docker failed | bad flag or profile |
reset | state reset | declined, not available on this server, no running instance to reset, or the configuration names two different servers | no terminal to ask on and no --yes |
config validate | no errors (warnings allowed) | errors found, or the file cannot be read | bad flag |
config profile ... | done | not found, already exists, cannot be read, or (for edit) no editor is set, the editor failed or the file no longer parses | unknown action, missing or invalid profile name, --port out of range |
config default-product | saved | the file cannot be written | not aws, gcp, az or oci |
env | variables printed | --shell is not supported | |
completion | script printed | the shell is not bash or zsh | |
snapshot ... | done | failed, or the server has no snapshot API yet | invalid 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, settingDOCKER_HOSTis 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/).
| Part | What it holds |
|---|---|
SKILL.md | Lifecycle, 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:
| Language | Repository |
|---|---|
| Java | testcontainers-floci |
| Node.js / TypeScript | testcontainers-floci-node |
| Python | testcontainers-floci-python |
| Go | testcontainers-floci-go |
| .NET | testcontainers-floci-dotnet |
Community
- 💬 Slack: quick questions and community chat
- 🗣️ GitHub Discussions: ideas, design tradeoffs, and proposals
- 🐛 Issues: bugs in this CLI or in the agent skill (emulator bugs go to that emulator's repository)
- 🛟 SUPPORT.md: where to get help, and what community support covers
- CONTRIBUTING.md · SECURITY.md · CODE_OF_CONDUCT.md · MAINTAINERS.md
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:
| Request | To | When |
|---|---|---|
| Release check | api.github.com | At 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 download | github.com (release assets) | Only when you run floci update or the install script |
| Image pull | Your container registry (Docker Hub by default) | When docker pulls an emulator image on floci start |
| Name lookup | DNS for localhost.floci.io, which answers 127.0.0.1 | When a tool uses the endpoint that floci env prints for AWS |
| Documentation pages | floci.io and raw.githubusercontent.com | When 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.