fhevm-cli is the local orchestration entrypoint for the fhEVM test stack.
It exists for three workflows:
- run a known stack target locally
- swap in local changes for one repo-owned group
- run multicopro topologies with deterministic generated state
The CLI owns all mutable runtime state under .fhevm/. Tracked compose and env files stay as templates.
For the boot flow diagram and invariants, see ARCHITECTURE.md.
Run from /Users/work/.codex/worktrees/75e6/fhevm/test-suite/fhevm:
bun install
bun run check
bun test
./fhevm-cli up --target latest-release --dry-run
./fhevm-cli up --target latest-release
./fhevm-cli test erc20
./fhevm-cli clean --imagesupresolves a target bundle, runs preflight, generates.fhevm, and boots the stackup --dry-runruns the same resolve and preflight path without mutating runtime statetestruns against the current stack; it does not recompile contractsdownstops the stackcleanremoves CLI-owned runtime stateclean --imagesalso removes CLI-owned local override images
latest-release: latest stable fhevm release plus checked-in companion defaultslatest-main: newest complete repo-owned main SHA bundle plus checked-in companion defaultsdevnettestnetmainnet
Only devnet, testnet, and mainnet resolve from GitOps. Non-network targets do not.
If you need to run a specific set of versions (e.g., v0.10.7 across the board), use --lock-file
to skip all target resolution and supply the full bundle yourself:
./fhevm-cli up --target latest-release --lock-file ./my-bundle.jsonThe lock file must contain every version key. Example:
{
"target": "latest-release",
"lockName": "pinned-v0.10.7.json",
"sources": ["manual"],
"env": {
"GATEWAY_VERSION": "v0.10.7",
"HOST_VERSION": "v0.10.7",
"COPROCESSOR_DB_MIGRATION_VERSION": "v0.10.7",
"COPROCESSOR_HOST_LISTENER_VERSION": "v0.10.7",
"COPROCESSOR_GW_LISTENER_VERSION": "v0.10.7",
"COPROCESSOR_TX_SENDER_VERSION": "v0.10.7",
"COPROCESSOR_TFHE_WORKER_VERSION": "v0.10.7",
"COPROCESSOR_ZKPROOF_WORKER_VERSION": "v0.10.7",
"COPROCESSOR_SNS_WORKER_VERSION": "v0.10.7",
"CONNECTOR_DB_MIGRATION_VERSION": "v0.10.7",
"CONNECTOR_GW_LISTENER_VERSION": "v0.10.7",
"CONNECTOR_KMS_WORKER_VERSION": "v0.10.7",
"CONNECTOR_TX_SENDER_VERSION": "v0.10.7",
"CORE_VERSION": "v0.13.0",
"RELAYER_VERSION": "v0.9.0",
"RELAYER_MIGRATE_VERSION": "v0.9.0",
"TEST_SUITE_VERSION": "v0.10.7"
}
}The --target flag still determines which compat policy applies. The lock file replaces only
the version resolution step — preflight, boot pipeline, and everything else run normally.
After resolving a target bundle, the CLI applies environment variable overrides: any
*_VERSION env var that matches a key in the resolved bundle replaces that version.
This is how CI works. The merge queue workflow:
- Builds Docker images tagged with the PR's HEAD SHA (e.g.,
abc1234) - Sets env vars like
COPROCESSOR_HOST_LISTENER_VERSION=abc1234 - Runs
./fhevm-cli up --target latest-release
The CLI resolves latest-release as the baseline (providing companion versions like
CORE_VERSION and RELAYER_VERSION that aren't built from this repo), then overlays the
SHA-tagged env vars for every component that was built from the PR.
Supported override keys (any subset):
GATEWAY_VERSION
HOST_VERSION
COPROCESSOR_DB_MIGRATION_VERSION
COPROCESSOR_HOST_LISTENER_VERSION
COPROCESSOR_GW_LISTENER_VERSION
COPROCESSOR_TX_SENDER_VERSION
COPROCESSOR_TFHE_WORKER_VERSION
COPROCESSOR_ZKPROOF_WORKER_VERSION
COPROCESSOR_SNS_WORKER_VERSION
CONNECTOR_DB_MIGRATION_VERSION
CONNECTOR_GW_LISTENER_VERSION
CONNECTOR_KMS_WORKER_VERSION
CONNECTOR_TX_SENDER_VERSION
CORE_VERSION
RELAYER_VERSION
RELAYER_MIGRATE_VERSION
TEST_SUITE_VERSION
Example — test a local coprocessor image without --override:
COPROCESSOR_HOST_LISTENER_VERSION=abc1234 \
COPROCESSOR_TFHE_WORKER_VERSION=abc1234 \
./fhevm-cli up --target latest-releaseThe resolved lock file records which keys were overridden in its sources field.
./fhevm-cli up --target latest-release
./fhevm-cli up --target latest-release --resume --from-step relayer
./fhevm-cli up --target latest-release --override coprocessor --profile local
./fhevm-cli up --target latest-release --coprocessors 2 --threshold 2
./fhevm-cli status
./fhevm-cli logs relayer
./fhevm-cli test input-proof
./fhevm-cli test erc20
./fhevm-cli down
./fhevm-cli clean --imagesUse --override to run local code for one repo-owned group on top of an otherwise versioned stack.
Supported groups:
coprocessorkms-connectorgateway-contractshost-contractstest-suite
./fhevm-cli up --target latest-release --override coprocessor --profile localTo build only specific services locally while pulling the rest from the registry:
./fhevm-cli up --target latest-release --override coprocessor:host-listener,tfhe-worker --profile localUse the short service suffix after the colon (e.g., host-listener not coprocessor-host-listener).
Multiple services are comma-separated. Services that share a Docker image are automatically
co-selected (e.g., host-listener includes host-listener-poller).
Note:
coprocessorandkms-connectorservices share a database. Per-service overrides work when your local changes don't include DB migrations. If your changes add or alter migrations, non-overridden services will fail against the mismatched schema — use--override coprocessor(full group) instead.
Available suffixes per group:
| Group | Suffixes |
|---|---|
coprocessor |
db-migration, host-listener, host-listener-poller, gw-listener, tfhe-worker, zkproof-worker, sns-worker, transaction-sender |
kms-connector |
db-migration, gw-listener, kms-worker, tx-sender |
gateway-contracts |
deploy-mocked-zama-oft, set-relayer-mocked-payment, sc-deploy, sc-add-network, sc-add-pausers, sc-trigger-keygen, sc-trigger-crsgen |
host-contracts |
sc-deploy, sc-add-pausers |
test-suite |
e2e-debug |
Repeat --override to override several groups at once:
# Two full groups
./fhevm-cli up --target latest-release --override coprocessor --override gateway-contracts --profile local
# Per-service across groups
./fhevm-cli up --target latest-release --override coprocessor:host-listener --override gateway-contracts:sc-deploy --profile local
# Mixed: per-service + full group
./fhevm-cli up --target latest-release --override coprocessor:host-listener --override kms-connector --profile localThe --profile flag applies to every override that doesn't specify its own profile.
You can mix per-service local builds with registry tag overrides:
COPROCESSOR_GW_LISTENER_VERSION=abc1234 \
./fhevm-cli up --target latest-release --override coprocessor:host-listener --profile localThis builds host-listener (and host-listener-poller) locally, pulls gw-listener at tag
abc1234, and pulls all other coprocessor services at the resolved target version.
Example:
./fhevm-cli up \
--target latest-release \
--coprocessors 2 \
--threshold 2 \
--instance-env 1:OTEL_SERVICE_NAME=coprocessor-1-local \
--instance-arg '1:tfhe-worker=--coprocessor-fhe-threads=4'Generated env, compose overlays, addresses, locks, and state all live under .fhevm/.
The CLI owns:
.fhevm/state.json.fhevm/locks/.fhevm/env/.fhevm/compose/.fhevm/addresses/
status shows the active stack state and any CLI-owned local build images.