Skip to content

CLI

The gaffer CLI scaffolds projections, runs them locally against fixtures or live KurrentDB, drives the debugger, and hosts the LSP and MCP servers.

CommandWhat it does
gaffer initCreate 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 authSign in to an environment’s OAuth identity provider and store the token. See [env.<name>.oauth].
gaffer mcpStart the gaffer MCP server over stdio. See MCP.
gaffer lspStart the gaffer LSP server over stdio. Used by the VS Code extension.
gaffer configManage user-level configuration (telemetry opt-out, anonymous identity).
gaffer versionPrint the gaffer version.

See the full command reference for every subcommand and flag, or run gaffer <command> --help.

On a terminal, gaffer scaffold and gaffer dev prompt for anything you didn’t pass on the command line:

  • gaffer scaffold asks for the path (when omitted) and any of source, partitioning, emit, and engine version not set via flags.
  • gaffer dev asks 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.

gaffer scaffold prompting for projection options

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 = 2
fixtures.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 required connection (the connection string, supporting ${VAR} expansion so credentials can stay out of the file) and an optional default bool. Exactly one environment may be the default. Select an environment with gaffer dev --env <name> or pick it from the interactive prompt; --env can 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 for gaffer dev <name> and other commands.
  • entry: path to the projection JS file, relative to the project root.
  • engine_version: 1 or 2. 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 from gaffer dev <name> --fixture <fixture-name>.

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

Terminal window
gaffer config telemetry status # show current opt-in state and identity
gaffer config telemetry off # opt out of telemetry
gaffer config telemetry on # opt back in

Project-level telemetry is opted out by setting telemetry = false at the top of gaffer.toml.

  • --json: structured output instead of the default text rendering. gaffer dev --json emits NDJSON, one object per line, each tagged with a type: info, event, result, error, fatal_error, summary, auth_required, and run_error. auth_required signals that a live run needs an interactive sign-in, and run_error that a run ended on a connection failure. Other commands emit a single JSON object.
  • --debug: starts the DAP debug server alongside gaffer dev. See Debugging projections.
  • --env <name>: select an environment from gaffer.toml to run gaffer dev against. Optional when one environment is marked default, 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 single gaffer dev invocation. Overrides --env and the configured environment.
  • --fixture <name> / --events <path>: pick a named fixture from gaffer.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 to gaffer scaffold and gaffer dev. See Interactive mode.

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=1 in the environment.
  • KURRENTDB_TELEMETRY_OPTOUT=1 in the environment.
  • DO_NOT_TRACK=1 in the environment.
  • VS Code’s telemetry.telemetryLevel set to off (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.