Skip to content
Back to cheatsheets

Cheatsheet

Huginn

The dashboard, scaffolder, and conventions auditor the rest of the pack falls back to.

View on GitHub

Quick reference for every command, option, and behavior. huginn is the estate CLI — a dashboard, auditor, and scaffolder for a whole folder of repos ($HUGINN_ROOT, default ~/github-repos), enumerated straight off disk. It’s config-driven, and its estate-wide commands skip exempt repos (exemptions.json + $HUGINN_FAMILY).

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


At a glance

CommandAliasesWhat it doesOptions
newScaffold a new repo to the full standard--public/--private, --desc "…", --scope web|k8s|infra, -n/--dry-run
initWrite a config with detected defaults--force
statusAt-a-glance dashboard of every repo-f/--fetch, --public, --private
prsOpen pull requests across the estate
branchesbrRepos with stray local branches--prune
doctorAudit repos against your conventions[repo], --fix, -v/--verbose
syncFast-forward every repo to its default branch
applyApply the label taxonomy to a repo<owner/repo> [scope]
conventionsconv, stdLook up the standardlabels [scope], ruleset, suite, doc
openOpen a repo (or a page) on GitHub[page]
help-h, --helpThe command menu
  • Inspect views (status prs branches doctor) describe the estate and are read-only by default. Two opt into action on a flag: branches --prune deletes merged local branches, and doctor --fix repairs the safe gaps.
  • Operate commands (sync apply) change things every run — sync pulls, apply writes labels.
  • new is the scaffolder: it creates a whole repo — local git, a private GitHub repo, guardrails, the doc suite, ruleset, and labels — in one shot.
  • Running huginn with no command prints the help menu — there is no default view. huginn has no --json/machine-readable output; it’s a human dashboard.

Requirements & global behavior

  • Requires bash, git, gh (authenticated), and jq. huginn is fast and local by default — plain git per repo; the network is used only where noted: gh for new, doctor, prs, apply, and status --public/--private, plus a plain git fetch for status --fetch. Commands that need the GitHub owner (doctor, prs, new, open, status --public/--private) resolve it from your config, or fall back to one gh api user call.

  • The estate is every top-level directory under $HUGINN_ROOT that contains a .git — scanned off disk, no owner check. Keep foreign/client repos out of the root so estate-wide commands don’t sweep them in.

  • Config model — settings resolve env var → config file → smart default. Run huginn init to write a config of detected defaults (gh login, git identity, estate paths), then edit it. File: ${XDG_CONFIG_HOME:-~/.config}/huginn/config (override with HUGINN_CONFIG).

    Key / env varDefaultPurpose
    HUGINN_OWNERyour gh loginGitHub owner of the estate repos
    HUGINN_ROOT~/github-reposdirectory of repos to manage
    HUGINN_EMAILyour git emailcommit email for new / doctor --fix
    HUGINN_NAMEyour git namecommitter name
    HUGINN_FAMILY(none)space-separated repos to exclude, merged with exemptions.json
    HUGINN_CONVENTIONSrepo-conventionsdir under HUGINN_ROOT holding labels.json / ruleset.json / docs-suite.json / exemptions.json
  • Exemptions — repos listed in your conventions repo’s exemptions.json, merged with any in $HUGINN_FAMILY, are skipped by the estate-wide commands (sync, doctor, prs, branches). status is the exception: the dashboard shows every repo under $HUGINN_ROOT, exempt or not.

  • Conventions, with a fallback — commands that read the standard (new, apply, conventions, doctor --fix) use your HUGINN_CONVENTIONS repo when present and fall back to the bundled templates/ otherwise, so they work out of the box.

  • NO_COLOR — set it (NO_COLOR=1 huginn …) to disable color; output is also plain automatically when piped or redirected (not a TTY).

  • Two-level helphuginn help (also -h/--help, and the no-argument default) for the menu; huginn <command> help for one command.

  • Exit codes0 on success; 1 on error (unknown command, no GitHub owner resolvable, a missing conventions file, or a usage error such as new/open/apply without its arguments). Note that findings are not errors: doctor exits 0 whether or not it turns up gaps.


Create

new <name>

Scaffold a brand-new repo to the full standard, end to end — nothing left half-wired. In one run: git init, the local business email, guardrail files (.agentgate.yml + workflow), the doc suite (README · LICENSE · CHANGELOG · ROADMAP · CONTRIBUTING), a .gitignore, a signed genesis commit, a private GitHub repo, the branch-protection ruleset (PR + agentgate + signatures), and the base + scope labels. Network (gh).

huginn new observatory
huginn new observatory --public
huginn new observatory --scope k8s --desc "DOKS monitoring add-on"
huginn new observatory --dry-run       # print the plan, create nothing
huginn new observatory -n              # same
OptionEffect
--publicCreate the GitHub repo public (default: private)
--privateCreate it private — the default, stated explicitly
--desc "…"Set the repo description
--scope <s>Also apply a label scope: web | k8s | infra (omit → base labels only)
-n, --dry-runPrint the plan and create nothing

Refuses to clobber: it stops if $HUGINN_ROOT/<name> already exists locally, or if <owner>/<name> already exists on GitHub. An unrecognized option is skipped with a warning rather than being treated as the repo name.


init

Write a config file (${XDG_CONFIG_HOME:-~/.config}/huginn/config) populated with detected defaults — your GitHub login, git email/name, and estate paths — then edit it to taste. An env HUGINN_* var always overrides the file.

huginn init
huginn init --force       # overwrite an existing config
OptionEffect
--forceOverwrite an existing config file

Keys written: HUGINN_OWNER · HUGINN_EMAIL · HUGINN_NAME · HUGINN_ROOT · HUGINN_FAMILY · HUGINN_CONVENTIONS.


Inspect

status

The flagship: a one-screen dashboard of every git repo in the estate — a row per repo. Fast and local by default.

Columns: REPO (local folder) · BRANCH (green = default, cyan = feature) · LAST (time since last commit) · STATUS. Status flags: ✓ clean · ● N changed · ↑N ahead ↓N behind · (no upstream) (branch tracks nothing) · ⚑N stashes · +N br (extra local branches) · ✉? no local email · ✉ <addr> (local email ≠ business address). It closes with a tally — repos · clean · dirty · on a feature branch, plus a wrong-email count when there is one.

huginn status
huginn status --fetch     # git fetch each repo first, for fresh ahead/behind (network)
huginn status -f
huginn status --public    # only public repos  (network — reads visibility via gh)
huginn status --private   # only private repos (network)
OptionEffect
-f, --fetchgit fetch each repo first so ahead/behind is fresh (network)
--public (--pub)Show only public repos (network — one gh repo list call)
--private (--priv)Show only private repos (network)

The visibility filter matches the local folder name against the owner’s repos, so a repo with no GitHub counterpart under that name drops out of both --public and --private.


prs

Every open pull request across the estate, one line each: repo, #, title, author. Handy for “what’s in flight / needs a merge?” after the agents have been working. Excludes exempt repos. Network (one search query).

huginn prs

(No options.)

Unlike the other views, prs is owner-scoped, not disk-scoped: it searches GitHub for the owner’s open PRs, so a repo you haven’t cloned into $HUGINN_ROOT still shows up. Capped at 100 open PRs.


branches

Every repo that carries local branches beyond its default, each marked (merged) or (unmerged). Descriptive by default — the only thing it deletes is what you opt into with --prune. Excludes exempt repos.

huginn branches
huginn br                 # alias
huginn branches --prune   # delete the merged-in local branches
OptionEffect
--pruneDelete the branches already merged into the default. Safe: git branch -d, never the current branch, never unmerged work.

Repos with no branches beyond the default are omitted. It ends with the number of repos carrying extras — or, under --prune, the number of branches deleted.


doctor [repo]

Audit repos against your conventions and surface only what’s off (pass -v to also list the ones that pass). Runs the whole estate, or a single repo if you name one. Network — reads each repo’s ruleset and security settings, so a full sweep takes a minute or two.

Checks:

  • Baseline (all repos): local user.email = the business address · a ruleset present.
  • Managed (AgentGate-wired) repos, additionally: agentgate required · signed commits required · .agentgate.yml present · secret scanning on (public repos) · the required doc suite present (README/LICENSE/CHANGELOG/ROADMAP/CONTRIBUTING) · no leftover classic branch protection (the estate standard is rulesets).

A repo counts as managed when it carries .github/workflows/agentgate.yml locally. Everything else is dormant/unwired: baseline checks only, and it prints a line only if one of those fails. Exempt repos are skipped entirely.

huginn doctor             # audit the whole estate
huginn doctor huginn      # audit a single repo (fast)
huginn doctor --fix       # auto-fix the safe gaps estate-wide
huginn doctor huginn --fix
huginn doctor -v          # also list repos that pass
OptionEffect
[repo]Audit a single repo instead of the whole estate
--fixAuto-fix the safe gaps only: set the business email, and re-apply the standard ruleset on any managed repo where it’s missing/drifted
-v, --verboseAlso list the repos that pass (default: only gaps)

Each flagged repo prints its gaps as short tags:

TagMeans
local-emailThe repo’s local user.email isn’t the business address
no-rulesetNo require-pr-to-default ruleset on the repo
gate-not-requiredThe ruleset doesn’t require a status check (agentgate)
sign-not-requiredThe ruleset doesn’t require signed commits
no-.agentgate.ymlThe workflow is wired up but its config file is missing
secret-scan-offPublic repo with secret scanning disabled
classic-protectionLegacy classic branch protection still set (standard is rulesets)
docs:<names>Required doc suite files missing, e.g. docs:ROADMAP,CONTRIBUTING
✚email, ✚rulesetWhat --fix repaired on this run

It closes with a tally — managed & compliant · with gaps · dormant, plus a fixed count under --fix. Gaps are findings, not failures: the exit code stays 0.


Operate

sync

Pull every repo to its default branch — fast-forward only. For each repo: check out the default branch, then git pull --ff-only. Skips repos with uncommitted changes (won’t clobber work) and exempt repos. Never force-pulls or merges — a repo that can’t fast-forward is reported, not touched. Ends with an updated / skipped / problems summary.

huginn sync

(No options.)


apply <owner/repo> [scope]

Apply the canonical label taxonomy to a repo — idempotent; delegates to apply-conventions.sh (your conventions repo’s, or the bundled one). Labels only: ruleset, git identity, metadata, milestones, and the board are separate steps (see huginn conventions doc). Network.

huginn apply youruser/website web
huginn apply youruser/cluster  k8s
huginn apply youruser/infra    infra
huginn apply youruser/notes            # no scope → the base label set only
ArgumentMeaning
<owner/repo>The target repo, e.g. youruser/website (required)
[scope]Optional domain labels on top of the base set: web | k8s | infra

Reference & navigate

conventions [topic]

Look up the standard you apply and are audited against — your HUGINN_CONVENTIONS repo, or the bundled defaults when there isn’t one. No argument prints an overview of what’s available.

huginn conventions            # overview
huginn conv                   # alias (also: huginn std)
huginn conventions labels     # the whole label taxonomy, in each label's real color
huginn conventions labels k8s # just one scope
huginn conventions ruleset    # the branch-protection rules in plain English
huginn conventions suite      # the required document suite
huginn conventions doc        # the full CONVENTIONS.md (paged)
SubtopicShows
labels [scope]The label taxonomy, in each label’s real color (scope = web | k8s | infra; omit for all)
rulesetThe branch-protection rules, in plain English
suite (docs)The required + recommended document suite (what doctor checks and new scaffolds)
doc (md)The full CONVENTIONS.md — via less when interactive, else straight to stdout
(no arg)Overview of what’s available

doc is the one subtopic with no bundled fallback: it needs a CONVENTIONS.md in your HUGINN_CONVENTIONS repo and says so if there isn’t one. An unrecognized subtopic prints the overview rather than erroring; an unrecognized label scope lists the groups that do exist.


open <repo> [page]

Open a repo — or one of its pages — on GitHub in your browser.

huginn open website           # the repo home
huginn open website rules     # settings → rulesets
huginn open website pr        # open pull requests
huginn open website security  # security & analysis settings
PageOpens
(none), homeThe repo home
pr (prs, pulls)The pull requests tab
settings (set)Repo settings
rules (ruleset)Settings → rulesets
security (sec)Settings → security & analysis
actions (ci)The Actions tab
issuesThe issues tab

Any other value is treated as a path under the repo (open <repo> <anything>…/<anything>).

The URL is always printed before launching, and huginn tries wslview, xdg-open, open, then explorer.exe — on a headless box where none exists, it says so and leaves you the URL to copy.


help

huginn                 # no command → the menu
huginn help            # the command menu
huginn -h              # same
huginn <command> help  # detail for one command (e.g. huginn doctor help)
huginn doctor --help   # -h / --help work per-command too

Recipes

# Lay of the land: where does every repo stand?
huginn status

# Fresh ahead/behind before a work session (network)
huginn status --fetch

# Just the public repos (e.g. before a hardening pass)
huginn status --public

# What's in flight across the estate right now?
huginn prs

# Where are my stray branches, and which are safe to clean?
huginn branches

# Actually delete the merged-in local branches
huginn branches --prune

# Audit the whole estate against the standard, gaps only
huginn doctor

# Audit one repo, fast
huginn doctor huginn

# Repair the safe gaps (business email + drifted rulesets)
huginn doctor --fix

# Catch every repo up to its default branch (ff-only, skips dirty)
huginn sync

# Stand up a new estate-compliant repo in one shot
huginn new observatory --scope k8s --desc "DOKS monitoring add-on"

# …but see the plan first
huginn new observatory --scope k8s --dry-run

# Put the canonical labels on a repo
huginn apply youruser/website web

# Remind myself what the ruleset actually enforces
huginn conventions ruleset

# Jump to a repo's ruleset settings in the browser
huginn open website rules

# Plain output for a log/pipe (no color)
NO_COLOR=1 huginn status