ferrogw CLI reference
ferrogw is the single binary that both runs the Ferro Labs AI Gateway server and provides a CLI for scaffolding config, validating it, diagnosing your environment, and managing a running instance over its Admin API.
Running ferrogw with no subcommand starts the server (backward compatible with ferrogw serve). Every other subcommand is a CLI operation.
Installation and runningโ
Build the binary from source (the Makefile produces ./bin/ferrogw), or run it through the published container image:
# Build from source
make build
./bin/ferrogw serve
# Or run with Docker
docker run -p 8080:8080 -e OPENAI_API_KEY=sk-... ghcr.io/ferro-labs/ai-gateway serve
The examples below assume ferrogw is on your PATH.
CLI subcommands that talk to a running gateway (status, plugins, admin, and the connectivity check in doctor) need a reachable gateway URL and, for protected routes, an API key. Both resolve from global flags or environment variables โ see Global flags and Environment variables.
Subcommand referenceโ
| Command | Purpose |
|---|---|
init | Scaffold a config file and generate a master key |
serve | Start the gateway server |
validate | Validate a config file (offline) |
doctor | Check environment, config, and connectivity |
status | Check health of a running gateway |
plugins | List plugins registered in a running gateway |
version | Print version information |
admin | Manage a running gateway over the Admin API |
ferrogw initโ
Creates a minimal configuration file and generates a master key used to authenticate with the dashboard and Admin API. The key is a random value with an fgw_ prefix.
Usage
ferrogw init [flags]
Flags
| Flag | Default | Description |
|---|---|---|
--config-format | yaml | Config file format: yaml or json |
-o, --output | config.yaml / config.json | Config file path |
--non-interactive | false | Skip prompts, use defaults |
Example
export OPENAI_API_KEY=sk-... ANTHROPIC_API_KEY=sk-ant-...
ferrogw init
Ferro Labs AI Gateway -- Setup
[OK] Created config.yaml
[OK] Targets from detected credentials: openai, anthropic
[OK] Master key: fgw_4f9c2a1b7e3d8650a1c4f0b29d6e7a83
[!] Save this key -- you need it for the Admin API and web application.
export MASTER_KEY=fgw_4f9c2a1b7e3d8650a1c4f0b29d6e7a83
Next steps:
1. Use this config: export GATEWAY_CONFIG=config.yaml
2. Set provider API keys (e.g. export OPENAI_API_KEY=sk-...)
3. Start the gateway: ferrogw serve
4. Check readiness: curl http://localhost:8080/readyz
The dashboard is served from the gateway's own root once it's running โ there's no separate /dashboard route or standalone web container to open.
The master key is shown once and is never written to disk โ store it securely (export it as MASTER_KEY or place it in your secret manager). If an existing config file is present, init leaves that file alone and generates no new master key: the key already in use for that deployment keeps working, and reprinting one would just be a credential that looks live and authenticates against nothing.
init always uses a fallback strategy, but its targets are scaffolded from whatever provider credentials the environment already holds โ the same detection ferrogw serve uses to auto-register providers โ so the file it writes is one this deployment can actually serve on the first request. Each detected provider (OPENAI_API_KEY, ANTHROPIC_API_KEY, and so on) becomes a target, in provider-registry order. If no provider credentials are found at all, init writes a single placeholder target (openai) with a comment explaining that a real key still needs to be set before the gateway can route anything.
ferrogw serveโ
Starts the gateway HTTP server. This is also the default action when you run ferrogw with no subcommand.
Usage
ferrogw serve
Example
GATEWAY_CONFIG=config.yaml \
MASTER_KEY=fgw_... \
OPENAI_API_KEY=sk-... \
ferrogw serve
The listen port comes from PORT (default 8080), and the config path from GATEWAY_CONFIG. See Environment variables.
ferrogw validateโ
Loads and validates a configuration file offline โ no running gateway is required. Accepts YAML or JSON (auto-detected). Validation runs two layers, both of which ferrogw serve runs too:
- Config-level โ target/strategy shape, alias chains, MCP server entries, and (since v1.4.0) that any plugin listed at multiple stages โ
response-cache,budget, andrequest-loggerall normally are โ carries byte-identical config at each stage it's listed at. - Binary-level โ every target's
virtual_keymust name a provider this binary registers, and every enabled plugin'snameandstagemust resolve against what this binary ships. A disabled plugin entry is not checked, matching whatserveskips too.
It does not resolve ${VAR} references, contact any provider, or check that credentials exist โ a target naming a real provider whose API key is only set in production is a valid config here. Exits non-zero if the file fails to load or fails either layer.
Usage
ferrogw validate <config-file>
Example
ferrogw validate config.yaml
[OK] Config is valid
Strategy: fallback
Targets: 2
Providers: openai, anthropic
With --format json or --format yaml, the parsed config is printed in that format instead of the summary table.
ferrogw doctorโ
Runs a set of environment, configuration, and connectivity checks to help diagnose setup problems. It reports:
- Provider API keys โ presence of
OPENAI_API_KEY,ANTHROPIC_API_KEY,GEMINI_API_KEY,GROQ_API_KEY,MISTRAL_API_KEY. - Configuration โ if
GATEWAY_CONFIGis set, loads the file and runs the same two-layer checkferrogw validatedoes: config-level validation (including the multi-stage plugin agreement rule) plus provider-id and plugin name/stage resolution against this binary. An invalid config is reported in red here too, matching whatvalidateandservewould reject. - Auth โ whether
MASTER_KEYis set. - Gateway connectivity โ a
GET /healthround-trip to the configured gateway URL, with latency.
doctor only exits non-zero when the loaded config is invalid. A missing provider key or an unreachable gateway are reported as findings, not treated as failures โ that's what makes ferrogw doctor safe to run against a laptop with no gateway running yet, while still catching a config a pipeline would need to fail on.
Usage
ferrogw doctor
Example
ferrogw doctor
Provider API Keys
[OK] openai
[OK] anthropic
[-] gemini
[-] groq
[-] mistral
2 found
Configuration
[OK] config.yaml (strategy=fallback, targets=2)
Auth
[OK] MASTER_KEY is set
Gateway Connectivity
[OK] http://localhost:8080 -- healthy (3ms)
ferrogw statusโ
Checks the health of a running gateway by calling GET /health, then reports the version and provider/model counts (when available from GET /admin/providers).
- Exits non-zero when the gateway is unreachable. The connection or timeout error is returned, not swallowed, so
ferrogw status || alertcan see it. A gateway that answers โ including a503-degraded/healthโ is still reachable and exits0; the degraded status is printed as a finding, not treated as a failure. - Diagnostics go to stderr. The "gateway unreachable" error included, keeping stdout the machine-readable channel so
ferrogw status | jqdoesn't have to sort output from errors. - Colour is suppressed off a terminal. Piping or redirecting output (or setting
NO_COLOR) drops the ANSI codes, so a log file orgrepsees plain ASCII text. --format json/--format yamlare refused.statusreports a human-readable narrative, not structured data โ there's no useful machine encoding for it, so asking for one is a command error rather than silently getting ANSI-decorated text back.- Takes no positional arguments. A stray one is rejected rather than silently ignored.
Usage
ferrogw status
Example
ferrogw status --gateway-url http://localhost:8080
[OK] http://localhost:8080 -- healthy (4ms)
Version: 1.5.2
Providers: 30 (412 models)
ferrogw pluginsโ
Lists the plugins registered in a running gateway instance, read from GET /admin/plugins.
Usage
ferrogw plugins
Example
ferrogw plugins
NAME TYPE ENABLED
---- ---- -------
word-filter guardrail yes
rate-limit middleware yes
request-logger middleware no
Use --format json or --format yaml for machine-readable output.
ferrogw versionโ
Prints build and runtime version information (version, commit, build date, Go version, OS/arch).
Usage
ferrogw version
Example
ferrogw version
Version 1.5.2
Commit a1b2c3d
Built 2026-06-01T12:00:00Z
Go go1.25.0
OS/Arch linux/amd64
ferrogw adminโ
Manages a running gateway over its Admin API. Requires a reachable gateway URL and an API key (the master key works). Configure them via --gateway-url / --api-key or the matching environment variables.
The admin command groups operations into four areas: keys, config, logs, and providers.
admin keys โ API key managementโ
| Command | Description |
|---|---|
admin keys list | List all API keys |
admin keys get <id> | Show details of one key |
admin keys create | Create a new key |
admin keys revoke <id> | Revoke a key |
admin keys rotate <id> | Rotate a key (issue a new key value) |
admin keys create flags:
| Flag | Default | Description |
|---|---|---|
--name | "" | Human-readable label for the key |
--scope | read_only | Key scope: admin or read_only |
--expires-in | "" | Expiry duration, e.g. 720h (30 days) |
ferrogw admin keys create --name ci-bot --scope read_only --expires-in 720h
admin keys create and admin keys rotate fail rather than print null when the Admin API answers 2xx with an empty body โ a payload was requested and none arrived, so that's reported as an error, not a silently empty result. admin keys revoke expects 204 No Content; anything else, including a body-less redirect, is reported as a failure instead of being read as success.
admin config โ runtime configurationโ
| Command | Description |
|---|---|
admin config get | Print the current runtime configuration |
admin config history | Show configuration change history |
admin config set --file <path> | Apply a new configuration (JSON file) |
admin config rollback <version> | Roll back to a previous config version |
admin config set requires --file pointing at a JSON config file (convert YAML first).
ferrogw admin config set --file new-config.json
ferrogw admin config rollback 3
admin logs โ request logsโ
| Command | Description |
|---|---|
admin logs list | List persisted request logs |
admin logs stats | Show aggregated log statistics |
admin logs list flags:
| Flag | Default | Description |
|---|---|---|
--limit | 50 | Maximum number of log entries to return |
ferrogw admin logs list --limit 100 --format json
admin providers โ provider inspectionโ
| Command | Description |
|---|---|
admin providers list | List registered providers and their model counts |
admin providers health | Show per-provider health status |
ferrogw admin providers list
ferrogw admin providers health --format json
Global flagsโ
These persistent flags apply to all subcommands.
| Flag | Env var | Default | Description |
|---|---|---|---|
--gateway-url | FERROGW_URL | http://localhost:8080 | Gateway base URL for Admin API calls |
--api-key | FERROGW_API_KEY | (falls back to MASTER_KEY) | Admin API key (sent as Authorization: Bearer) |
--format | โ | table | Output format: table, json, or yaml |
The API key resolves in order: --api-key flag โ FERROGW_API_KEY โ MASTER_KEY. This means once you export MASTER_KEY, the admin commands authenticate without any extra flag.
--format only changes output for the commands that return structured data โ validate, plugins, version, and the admin subcommands. init, doctor, and status render a human-readable report only and refuse any --format other than table.
Environment variablesโ
ferrogw reads the following environment variables. Server-side variables are read by serve; CLI variables are read by the Admin API client.
| Variable | Read by | Description |
|---|---|---|
GATEWAY_CONFIG | serve, doctor | Path to the config file (YAML or JSON) |
GATEWAY_ENV | serve | Set to production (case-insensitive) to turn on production safety checks โ refuses ALLOW_UNAUTHENTICATED_PROXY=true and a * in CORS_ORIGINS; warns on RATE_LIMIT_RPS=0, ENABLE_PPROF, and the in-memory key store |
PORT | serve | HTTP listen port (default 8080) |
MASTER_KEY | serve, admin CLI | Bootstrap/break-glass admin credential; generated by ferrogw init |
FERROGW_URL | CLI | Gateway base URL when --gateway-url is not set |
FERROGW_API_KEY | CLI | Admin API key when --api-key is not set |
ALLOW_UNAUTHENTICATED_PROXY | serve | Set to true to leave proxy routes unauthenticated (development only โ refused when GATEWAY_ENV=production) |
ENABLE_PPROF | serve | Set to true to mount /debug/pprof/* profiling routes |
Provider credentials (OPENAI_API_KEY, ANTHROPIC_API_KEY, and the rest) are documented in Provider configuration. For the full server configuration schema, see Configuration.