CLI
The gaffer CLI scaffolds projections, runs them locally against fixtures or live KurrentDB, drives the debugger, and hosts the LSP and MCP servers.
Commands
Section titled “Commands”| Command | What it does |
|---|---|
gaffer init | Create gaffer.toml in the current directory. |
gaffer scaffold <path> | Create a projection file at <path> and register it in gaffer.toml. |
gaffer dev <name> | Run a projection against fixtures (--fixture <name> or --events <path>) or live KurrentDB. |
gaffer info <name> | Print the projection’s details: source, partitioning, declared fixtures, engine version, matched events, and any diagnostics. |
gaffer auth | Sign in to an environment’s OAuth identity provider and store the token. See [env.<name>.oauth]. |
gaffer mcp | Start the gaffer MCP server over stdio. See MCP. |
gaffer lsp | Start the gaffer LSP server over stdio. Used by the VS Code extension. |
gaffer config | Manage user-level configuration (telemetry opt-out, anonymous identity). |
gaffer version | Print the gaffer version. |
See the full command reference for every subcommand and flag, or run gaffer <command> --help.
Interactive mode
Section titled “Interactive mode”On a terminal, gaffer scaffold and gaffer dev prompt for anything you didn’t pass on the command line:
gaffer scaffoldasks for the path (when omitted) and any of source, partitioning, emit, and engine version not set via flags.gaffer devasks which projection to run (when omitted) and which event source to use when none is pinned via--events,--fixture,--connection, or--env. The picker lists every declared fixture and configured environment; with a single source it’s used without asking.
Anything you pass explicitly (a positional or a flag) is taken as-is and never re-prompted; only the gaps are asked. Pass --yes (-y) to skip prompts and accept defaults, the same thing that happens automatically when input isn’t a terminal (pipes, CI), so scripts keep working unchanged. Press Ctrl-C or Esc on any prompt to cancel.

Project configuration
Section titled “Project configuration”Each gaffer project has a gaffer.toml at its root, created by gaffer init. It declares the projections in the project, their entry files, and any named fixtures:
[env.local]connection = "kurrentdb://localhost:2113?tls=false"default = true
[[projection]]name = "order-count"entry = "projections/order-count.js"engine_version = 2fixtures.happy = "fixtures/orders.json"fixtures.full = "fixtures/orders-full.json"Top-level keys:
[env.<name>]: an environment, naming a KurrentDB connection. Each block has a requiredconnection(the connection string, supporting${VAR}expansion so credentials can stay out of the file) and an optionaldefaultbool. Exactly one environment may be the default. Select an environment withgaffer dev --env <name>or pick it from the interactive prompt;--envcan be omitted on a non-interactive run when one environment is the default. An environment can also authenticate with OAuth, an X.509 client certificate, or basic credentials; see Authentication. See Environment file and the gaffer.toml reference.
engine_version is set per-[[projection]] (1 or 2), not at the top level.
Per-projection ([[projection]]):
name: the lookup key forgaffer dev <name>and other commands.entry: path to the projection JS file, relative to the project root.engine_version:1or2. Required on every projection. V1 is for legacy compatibility; V2 is the default for new projections.fixtures.<name>: path to a JSON events file, relative to the project root. Referenced fromgaffer dev <name> --fixture <fixture-name>.
Environment file (.env)
Section titled “Environment file (.env)”A .env file at the project root is loaded into the environment when gaffer starts, so secrets stay out of gaffer.toml and out of version control. Reference them in an environment’s connection with ${VAR}:
[env.local]connection = "kurrentdb://admin:${DB_PASSWORD}@localhost:2113".env supplies any environment variable gaffer reads, including the telemetry and update-check opt-outs below.
A per-environment .env.<env> file (matching the selected [env.<name>]) overlays the base .env, so each environment can carry its own credentials. The precedence, highest first, is the shell environment, then .env.<env>, then the base .env. A variable set in your shell, or injected by CI, is never overwritten by either file.
User configuration
Section titled “User configuration”User-level settings (telemetry opt-out and a per-install anonymous identity) live in a platform-specific config directory:
- Linux:
$XDG_CONFIG_HOME/gaffer/config.toml(default~/.config/gaffer/config.toml). - macOS:
~/Library/Application Support/gaffer/config.toml. - Windows:
%AppData%\gaffer\config.toml.
Set GAFFER_CONFIG_DIR to override.
Manage with gaffer config:
gaffer config telemetry status # show current opt-in state and identitygaffer config telemetry off # opt out of telemetrygaffer config telemetry on # opt back inProject-level telemetry is opted out by setting telemetry = false at the top of gaffer.toml.
Common flags
Section titled “Common flags”--json: structured output instead of the default text rendering.gaffer dev --jsonemits NDJSON, one object per line, each tagged with atype:info,event,result,error,fatal_error,summary,auth_required, andrun_error.auth_requiredsignals that a live run needs an interactive sign-in, andrun_errorthat a run ended on a connection failure. Other commands emit a single JSON object.--debug: starts the DAP debug server alongsidegaffer dev. See Debugging projections.--env <name>: select an environment fromgaffer.tomlto rungaffer devagainst. Optional when one environment is markeddefault, or on a terminal where you’re prompted to pick; required for non-interactive runs with no default.--connection: ad-hoc connection string for a singlegaffer devinvocation. Overrides--envand the configured environment.--fixture <name>/--events <path>: pick a named fixture fromgaffer.toml, or point at a JSON events file directly. These offline sources are mutually exclusive with the live ones (--env/--connection); combining the two is a usage error.--yes/-y: skip interactive prompts and accept defaults. Applies togaffer scaffoldandgaffer dev. See Interactive mode.
Telemetry
Section titled “Telemetry”The CLI emits anonymous usage telemetry by default. See the telemetry notice for the full list of what’s collected.
Opt out at the user level via any of:
gaffer config telemetry off(persists to the user config file).GAFFER_TELEMETRY_OPTOUT=1in the environment.KURRENTDB_TELEMETRY_OPTOUT=1in the environment.DO_NOT_TRACK=1in the environment.- VS Code’s
telemetry.telemetryLevelset tooff(the extension and CLI both respect it).
The environment-variable opt-outs are read from your shell or a project .env.
Opt out at the project level by setting telemetry = false in gaffer.toml.