Skip to content
Back to cheatsheets

Cheatsheet

Geri

The hunter — outdated dependencies, security advisories, and drift, run down in one sweep.

View on GitHub

Quick reference for every command, option, and behavior. geri is the hunter of your GitHub estate — it sweeps every repo under the estate root for security and freshness risk (open Dependabot alerts, outdated deps, unpinned/outdated Actions) and reports the estate-wide picture in one pass. Everything is derived live from the GitHub API via gh (plus a bounded local scan) — no database, no cache, no stored state.

For the narrative version see the README; for per-command detail in the terminal, run geri <command> help.


At a glance

CommandAliasesWhat it doesOptions
alerts(none)Open Dependabot security alerts, estate-wide, most-severe first[repo], --flat
deps(none)Outdated dependencies: unmonitored manifests + open Dependabot update PRs[repo]
actions(none)Third-party Actions pinned to a moving tag / behind latest[repo]
hunt(none)Combined summary — alerts · deps · actions, per repo--md
init(none)Write a geri config with detected defaults--force
help-h, --helpThe command menu
  • geri is entirely read-only. It reports risk — where you’re exposed, what’s behind, what’s unpinned — and never touches a repo, its settings, or its Actions. There is no --apply; fixing is Dependabot’s job (or a later geri phase). Its sibling freki is the one with teeth.
  • Everything is estate-scoped: one sweep across every repo under $GERI_ROOT, minus exemptions. Pass a [repo] name to alerts/deps/actions to narrow it to a single repo.
  • Running geri with no command prints the menu (same as geri help).

Requirements & global behavior

  • Requires bash, git, gh (authenticated), and jq — all four. Unlike a local-only tool, every command reaches GitHub through gh; there’s no offline fallback. deps and actions add a bounded local scan (manifests / workflow files) on top of one network call.
  • Alerts need security-read access, and degrade gracefully. alerts (and the alerts slice of hunt) call gh api .../dependabot/alerts per repo. When that doesn’t come back as a JSON array — Dependabot alerts disabled, or you lack security-read on the repo — geri counts that repo separately as “checked without Dependabot alerts enabled” rather than erroring or crashing. Disabled and no-access fold into the same tally; enable it in the repo’s Settings → Code security to have geri cover it. hunt simply skips such repos silently.
  • Config model — settings resolve env GERI_* → config file → smart default. The file is ${XDG_CONFIG_HOME:-~/.config}/geri/config (override with GERI_CONFIG); run geri init to write one. Keys: GERI_ROOT (default ~/github-repos), GERI_OWNER (default your gh login, resolved lazily), GERI_FAMILY (repos to exclude), GERI_CONVENTIONS (dir holding exemptions.json). If ~/.config/huginn/config exists and the matching GERI_* value is unset, geri falls back to huginn’s HUGINN_ROOT/HUGINN_OWNER/HUGINN_FAMILY/HUGINN_CONVENTIONS — a huginn user gets a working geri with zero setup.
  • Exemptions — the estate is every directory under $GERI_ROOT containing a .git. A repo exempt from huginn is exempt from the hunt too: geri merges exemptions.json (in the conventions dir) with $GERI_FAMILY/$HUGINN_FAMILY and skips those repos everywhere. Same list the ravens skip.
  • NO_COLOR — set it (NO_COLOR=1 geri …) to disable color. Output is also automatically plain when piped or redirected (not a TTY).
  • Two-level helpgeri help for the menu, geri <command> help (or -h/--help) for one command.
  • Read-only, no --json. Output is terminal by default; only hunt offers a machine-portable form, --md (a Markdown briefing). There is no JSON emitter in v0.1.
  • Exit codes0 on success; 1 on an unknown command, or when no GitHub owner can be resolved (not configured and gh api user fails). An unknown per-command flag is warned and ignored (ignoring unknown option: …), not fatal.

Hunt

alerts

Open Dependabot security alerts across the estate, most-severe first. Grouped by repo (worst repo first) by default, or one flat severity-sorted list with --flat. One gh api .../dependabot/alerts call per repo (excluding exempt repos), the same cost class as huginn doctor. The headline view — where am I exposed, everywhere, right now.

Severity order: critical · high · medium · low.

geri alerts                 # every repo, grouped by repo (worst first)
geri alerts --flat          # one severity-sorted list across the whole estate
geri alerts day-one         # just one repo
geri alerts day-one --flat  # a single repo, flat list
OptionEffect
[repo]Check a single repo instead of the whole estate
--flatOne severity-sorted list across the estate (worst repo first), instead of grouped by repo

A repo with Dependabot alerts disabled (or that you can’t read) is tallied as “checked without Dependabot alerts enabled” and reported in the footer — counted, never treated as an error.


deps

Outdated dependencies across the estate, two signals:

  • unmonitored — a repo carries a manifest (package.json, go.mod, Cargo.toml, …) but has no .github/dependabot.yml watching it; its staleness is invisible until one is added. (Bounded local scan: depth 2, skips node_modules/vendor/dist/build.)
  • open update PRs — Dependabot’s own open version-update PRs, oldest first. One gh search prs call covers the whole estate, the same one-call pattern as huginn prs.
geri deps                   # the whole estate
geri deps huginn            # just one repo
OptionEffect
[repo]Check a single repo instead of the whole estate

actions

Third-party GitHub Actions pinned to a moving tag (e.g. @v4) instead of a commit SHA, or pinned to a tag that’s behind the action’s latest release — the supply-chain-hygiene gap repo-conventions §3 calls for (pin actions to a SHA). Your own (brett-buskirk/*) actions are excluded; the guidance is scoped to third parties.

A bounded local scan of each repo’s .github/workflows/*.yml for uses: lines, then one gh api .../releases/latest call per unique action (deduped across the estate) to tell a merely-unpinned action apart from an actually-outdated one. A ref that isn’t version-shaped (@main, @beta) is flagged as tracking a branch/channel — arguably the riskiest kind, since it can change without notice (shown in red, sorted to the top).

geri actions                # the whole estate
geri actions heimdall       # just one repo
OptionEffect
[repo]Check a single repo instead of the whole estate

hunt

The combined what needs running down summary — alerts, deps, and actions, per repo, with an estate headline (N alerts · M outdated dep signals · K unpinned actions). Lighter than running all three commands: it skips the outdated-vs-latest lookup geri actions does (it just counts unpinned usages) — run geri actions for that detail. The most expensive geri command: a full sweep (one alerts call per repo, one PR search, a local workflow scan).

--md emits a clean Markdown briefing to stdout instead of the terminal view — redirect it to a file for something shareable, the way muninn digest --md works.

geri hunt                   # terminal summary
geri hunt --md              # Markdown briefing to stdout
geri hunt --md > hunt.md    # …saved as a shareable file
OptionEffect
--mdEmit a Markdown briefing to stdout instead of the terminal view

Configure

init

Write a config file (${XDG_CONFIG_HOME:-~/.config}/geri/config) with detected defaults — your GitHub login and estate root — then edit it. Won’t clobber an existing config unless you pass --force. Config keys (an env GERI_* var overrides the file): GERI_ROOT · GERI_OWNER · GERI_FAMILY · GERI_CONVENTIONS. If ~/.config/huginn/config exists and a GERI_* value is unset, geri falls back to huginn’s settings, so this file only needs the keys you want to diverge on.

geri init                   # write a config (no-op if one already exists)
geri init --force           # overwrite an existing config
OptionEffect
--forceOverwrite an existing config file instead of leaving it be

help

geri help              # the command menu
geri -h                # same
geri --help            # same
geri <command> help    # detail for one command (e.g. geri alerts help)

Running geri with no arguments prints the menu.


Recipes

# Where am I exposed, everywhere, right now?
geri alerts

# One severity-sorted list across the estate — worst first
geri alerts --flat

# Alerts for just one repo (e.g. the one with a live Dependabot alert)
geri alerts day-one

# What's behind everywhere — unwatched manifests + open update PRs
geri deps

# Which third-party actions aren't SHA-pinned (or are outdated)?
geri actions

# The full picture in one sweep — alerts · deps · actions
geri hunt

# A shareable Markdown briefing to hand off or commit
geri hunt --md > hunt-$(date +%F).md

# First-run setup — write a config with detected defaults
geri init

# Plain output for a log or pipe (no color)
NO_COLOR=1 geri hunt