Configuration & aliases

ggc reads configuration from one of:

  1. $XDG_CONFIG_HOME/ggc/config.yaml
  2. ~/.config/ggc/config.yaml (default on Linux/macOS)
  3. ~/.ggcconfig.yaml (legacy path; still respected for older installs)

The first file that exists wins. If none exists, built-in defaults are used. On Windows the path resolves via %APPDATA%\ggc\config.yaml.

Editor autocomplete (JSON Schema)

A JSON Schema for the config file is published alongside these docs: https://bmf-san.github.io/ggc/ggc-config.schema.json. Add this header to your YAML to get autocomplete, hover docs, and validation in VS Code (with the YAML extension) and anything else that speaks SchemaStore conventions:

# yaml-language-server: $schema=https://bmf-san.github.io/ggc/ggc-config.schema.json
meta:
  version: v8.3.0
  # ...

The schema mirrors the Go struct (internal/config.Config); a unit test guards against drift between the two, so what's published is what ggc actually reads.

Anatomy

meta:
  version: v8.3.0     # auto-maintained by ggc
  commit: abcdef1     # auto-maintained by ggc
  created-at: 2025-01-15_12:34:56

ui:
  color: true

git:
  default-remote: origin
  default-branch: main

aliases:
  ship: status && commit amend --no-edit && push force
  cleanup: branch delete merged

interactive:
  profile: default   # one of: default | emacs | vi | readline

meta.* is rewritten by ggc on startup; don't edit it by hand.

Aliases

An alias is a named sequence of ggc commands separated by &&. Anything you can type in the prompt you can put behind an alias.

ggc ship

runs the three commands above in order, stopping at the first failure.

Placeholders

Numeric placeholders let an alias accept arguments:

aliases:
  commit-msg: "commit -m '{0}'"
  feature:    ["branch checkout {0}", "push {0}"]

Then:

ggc commit-msg "Fix bug"
ggc feature main

See the alias validation grammar for the exact rules (nesting, escaping, reserved names).

Keybindings

Profiles

Pick a profile in one line:

interactive:
  profile: emacs
Profile Feel
default Curated ggc defaults (recommended)
emacs GNU readline-style
vi Modal, hjkl navigation
readline Strict GNU readline compatibility

Overriding individual keys

Under interactive.keybindings you can override any binding by its logical name:

interactive:
  keybindings:
    move_up: "ctrl+p"
    move_down: "ctrl+n"
    accept: "enter"
    cancel: "esc"
    toggle_workflow: "ctrl+w"

Supported key notations

Three equivalent forms are accepted; pick whichever reads best:

Notation Example
ctrl+ ctrl+p
C- C-p
raw caret ^P

alt+ / M- and shift+ work the same way. Function keys (f1..f12), arrow keys (up, down, left, right), and named keys (enter, esc, tab, space, backspace) are all recognized.

Layered overrides

The config is evaluated in this order, later layers winning:

  1. interactive.profile baseline
  2. interactive.keybindings (global)
  3. interactive.<os>darwin / linux / windows
  4. interactive.contexts.<ctx> — e.g. contexts.picker, contexts.search
  5. interactive.terminals.<term> — e.g. terminals.alacritty, terminals.iterm2

Example: use emacs everywhere, but tweak move_up on macOS only:

interactive:
  profile: emacs
  darwin:
    keybindings:
      move_up: "ctrl+p"

Inspecting the resolved keymap

ggc config list
ggc config get interactive.keybindings
ggc config get interactive.darwin.keybindings

If you're unsure what key your terminal is sending, run:

ggc debug-keys

and press keys — it prints the raw escape sequences.

Editing

ggc config edit   # opens the config file in $EDITOR
ggc config path   # prints the resolved path
ggc config list   # print the fully-merged config

History

ggc persists each executed command to a per-user JSONL store so the interactive prompt's recall (Ctrl+P / Ctrl+N), incremental search (Ctrl+R) and the ggc history subcommands have something to read.

history:
  enabled: true        # default; set to false to disable writes entirely
  max-entries: 1000    # default; cap before truncate-rewrite kicks in

Behaviour:

  • Reads are always available, even when enabled: false — useful for inspecting prior commands while temporarily off the record.
  • GGC_NO_HISTORY=1 in the environment forces disabled state and overrides the config value. Handy in one-off shells / CI.
  • The store lives under $TMPDIR/ggc-<uid>/history.jsonl on Unix-like systems and UserCacheDir() on Windows. Use ggc history clear to wipe it.
  • The history subcommand itself (including history clear, history search ..., history last ...) is never recorded so navigating history doesn't pollute it.
  • Inside the interactive prompt, the history picker and Ctrl+R reverse-i-search share the same store and use the same deduplication policy (newest occurrence wins per display string). The picker shows up to 30 recent unique entries; Ctrl+R searches up to 200.
  • Inside the Ctrl+R overlay Ctrl+C cancels the overlay rather than quitting ggc; the global "quit" meaning is restored as soon as you exit the overlay.

tmux

Under tmux, most terminals mangle the modifier prefix unless xterm-keys is on. Add to ~/.tmux.conf:

set -g xterm-keys on

Then reload tmux. Without this, ctrl+arrow / alt+... will arrive as bare arrow keys.