Skip to main content

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.

note

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โ€‹

CommandPurpose
initScaffold a config file and generate a master key
serveStart the gateway server
validateValidate a config file (offline)
doctorCheck environment, config, and connectivity
statusCheck health of a running gateway
pluginsList plugins registered in a running gateway
versionPrint version information
adminManage 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

FlagDefaultDescription
--config-formatyamlConfig file format: yaml or json
-o, --outputconfig.yaml / config.jsonConfig file path
--non-interactivefalseSkip 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.

warning

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, and request-logger all normally are โ€” carries byte-identical config at each stage it's listed at.
  • Binary-level โ€” every target's virtual_key must name a provider this binary registers, and every enabled plugin's name and stage must resolve against what this binary ships. A disabled plugin entry is not checked, matching what serve skips 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_CONFIG is set, loads the file and runs the same two-layer check ferrogw validate does: 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 what validate and serve would reject.
  • Auth โ€” whether MASTER_KEY is set.
  • Gateway connectivity โ€” a GET /health round-trip to the configured gateway URL, with latency.
note

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 || alert can see it. A gateway that answers โ€” including a 503-degraded /health โ€” is still reachable and exits 0; 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 | jq doesn'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 or grep sees plain ASCII text.
  • --format json/--format yaml are refused. status reports 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โ€‹

CommandDescription
admin keys listList all API keys
admin keys get <id>Show details of one key
admin keys createCreate 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:

FlagDefaultDescription
--name""Human-readable label for the key
--scoperead_onlyKey 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
note

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โ€‹

CommandDescription
admin config getPrint the current runtime configuration
admin config historyShow 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โ€‹

CommandDescription
admin logs listList persisted request logs
admin logs statsShow aggregated log statistics

admin logs list flags:

FlagDefaultDescription
--limit50Maximum number of log entries to return
ferrogw admin logs list --limit 100 --format json

admin providers โ€” provider inspectionโ€‹

CommandDescription
admin providers listList registered providers and their model counts
admin providers healthShow per-provider health status
ferrogw admin providers list
ferrogw admin providers health --format json

Global flagsโ€‹

These persistent flags apply to all subcommands.

FlagEnv varDefaultDescription
--gateway-urlFERROGW_URLhttp://localhost:8080Gateway base URL for Admin API calls
--api-keyFERROGW_API_KEY(falls back to MASTER_KEY)Admin API key (sent as Authorization: Bearer)
--formatโ€”tableOutput format: table, json, or yaml
note

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.

note

--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.

VariableRead byDescription
GATEWAY_CONFIGserve, doctorPath to the config file (YAML or JSON)
GATEWAY_ENVserveSet 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
PORTserveHTTP listen port (default 8080)
MASTER_KEYserve, admin CLIBootstrap/break-glass admin credential; generated by ferrogw init
FERROGW_URLCLIGateway base URL when --gateway-url is not set
FERROGW_API_KEYCLIAdmin API key when --api-key is not set
ALLOW_UNAUTHENTICATED_PROXYserveSet to true to leave proxy routes unauthenticated (development only โ€” refused when GATEWAY_ENV=production)
ENABLE_PPROFserveSet 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.