Interactive tools for submodule dashboards and bulk git operations across
repositories with .gitmodules.
make compile # py_compile the collector
make install # bins → ~/.local/bin, lib → ~/.local/share/github-utilsAlso installed by the monorepo make install-utilities (utilities/shell/github-utils fan-out).
python3,gitfzf— interactive TUI / multi-select (brew install fzf)gh— optional; required for open PRs and Actions (gh auth login)
Docs (Read the Docs / Sphinx): make docs or see docs/index.md. Config: .readthedocs.yaml.
Uses infra-config.yaml for shared settings (see k8-lib README). Every tool accepts --config <path>.
Git root is auto-detected from cwd. Works in any repo with .gitmodules.
| Command | Purpose |
|---|---|
submodule-status |
Dashboard: submodules, worktrees + ages, open PRs/branches, Actions; click through to GitHub |
submodule-commit |
Interactive bulk commit/push for dirty submodules with nested bubbling |
submodule-status # fzf dashboard (table if no fzf / not a TTY)
submodule-status --web # clickable HTML dashboard in the browser
submodule-status --table # stdout table (OSC-8 links on a TTY)
submodule-status --json # machine-readable snapshot
submodule-status --local # skip GitHub (no gh required)
submodule-status Portfolio/Apps # path prefix filter- Every submodule (recursive
.gitmodules), plus the umbrella repo - Current branch, SHA, dirty counts
git worktree listper repo, with ages (HEAD commit / dir mtime)- Open PRs (number, branch, title, check rollup) via
gh pr list - Recent Actions runs via
gh run list - Click/key: repo, pulls, Actions, branch, local folder
| Key | Action |
|---|---|
| enter / double-click | Open GitHub repo |
| ctrl-p | Open pull requests |
| ctrl-a | Open Actions |
| ctrl-b | Open current branch |
| ctrl-w | Open local checkout folder |
| ctrl-e | Open HTML dashboard |
| ctrl-r | Refresh |
| q / esc | Quit |
Preview and --table emit OSC-8 hyperlinks (iTerm2, kitty, WezTerm, Ghostty, VS Code). --web is the fully clickable view.
GitHub JSON is cached under ~/.cache/submodule-status/ (default TTL 90s). --refresh bypasses it.
submodule-commit # Scan, select via fzf, commit + push
submodule-commit --all # Commit all dirty submodules (skip fzf)
submodule-commit --dry-run # Preview planned actions
submodule-commit --no-push # Commit locally, skip git push
submodule-commit -m "my message" # Provide commit message non-interactively
submodule-commit --all -m "wip" # Fully non-interactive
submodule-commit --config my.yaml # Use specific config file- Scan — recursively walks
.gitmodulesat every nesting level, checks each submodule for staged, modified, and untracked files - Select — fzf multi-select with TAB to toggle; shows change counts and a
git status --shortpreview pane - Commit — processes deepest-first so nested submodule refs bubble up correctly:
git add .in the submodulegit commit -m <message>git push origin HEADgit add <submodule>in the parent repo
- Parent — after all submodules, offers to commit and push the updated refs in the root repo
If your repo has submodules inside submodules, the tool processes them deepest-first. After committing a deeply nested submodule, it stages the updated ref in the parent, so that when the parent is committed next, it captures the new pointer.