Skip to content

Instantly share code, notes, and snippets.

@ericboehs
Created November 19, 2025 21:00
Show Gist options
  • Select an option

  • Save ericboehs/08143ade3c5bca6002eb803576704eed to your computer and use it in GitHub Desktop.

Select an option

Save ericboehs/08143ade3c5bca6002eb803576704eed to your computer and use it in GitHub Desktop.
gh-pm: Interactive GitHub Project Manager with fzf - Cached issue list with edit, status update, and sorting capabilities
#! /usr/bin/env bash
set -e
set -u
set -o pipefail
export CACHE_FILE="${XDG_CACHE_HOME:-$HOME/.cache}/gh-pm-list.txt"
mkdir -p "$(dirname "$CACHE_FILE")"
# Only refresh if cache is older than 5 minutes, missing, or empty
if [[ ! -f "$CACHE_FILE" ]] || [[ ! -s "$CACHE_FILE" ]] || [[ -n "$(find "$CACHE_FILE" -mmin +5 2>/dev/null)" ]]; then
echo "Fetching issues..."
gh pm list --limit 100 > "$CACHE_FILE"
fi
cat "$CACHE_FILE" | fzf \
--delimiter='\s\s+' \
--tac \
--multi \
--header-lines=1 \
--header='Enter: edit | Ctrl-e: echo | Ctrl-s: change status | Ctrl-r: reload | Alt-i: sort ID | Alt-d: default' \
--bind 'enter:execute(cmds=""; for issue in {+1}; do cmds="$cmds -c \"Octo issue edit $issue\""; done; eval nvim $cmds)+deselect-all' \
--bind 'ctrl-e:become(printf "%s\n" {+1})' \
--bind 'ctrl-s:execute(
new_status=$(ruby -ryaml -e "YAML.load_file(\".gh-pm.yml\")[\"fields\"][\"status\"][\"values\"].each {|k,v| puts \"#{k}:#{v}\"}" | \
fzf --delimiter=":" --with-nth=2 --header="Select status" | cut -d: -f1)
if [[ -n "$new_status" ]]; then
for issue in {+1}; do
gh pm move "$issue" --status "$new_status"
done
fi
)+reload(gh pm list --limit 100 | tee "$CACHE_FILE")+deselect-all' \
--bind 'ctrl-r:reload(gh pm list --limit 100 | tee "$CACHE_FILE")' \
--bind 'alt-i:reload(sh -c "head -1 \"$CACHE_FILE\"; tail -n +2 \"$CACHE_FILE\" | sort -n")' \
--bind 'alt-d:reload(cat "$CACHE_FILE")' \
--bind 'ctrl-h:execute-silent(tmux select-pane -L)' \
--bind 'ctrl-j:execute-silent(tmux select-pane -D)' \
--bind 'ctrl-k:execute-silent(tmux select-pane -U)' \
--bind 'ctrl-l:execute-silent(tmux select-pane -R)'
@ericboehs
Copy link
Author

gh-pm - Interactive GitHub Project Manager

A cached, interactive fzf interface for managing GitHub Project issues.

Prerequisites

  • gh CLI with the pm extension (gh extension install yahsan2/gh-pm)
  • fzf for interactive selection
  • nvim with Octo.nvim for editing issues
  • .gh-pm.yml config file in your project directory for status changes

Features

  • Smart caching: Refreshes issue list only when cache is older than 5 minutes
  • Multi-select: Select multiple issues for batch operations
  • Interactive keybindings:
    • Enter - Edit selected issues in neovim (Octo)
    • Ctrl-e - Echo issue numbers to stdout
    • Ctrl-s - Change status of selected issues
    • Ctrl-r - Force reload from GitHub
    • Alt-i - Sort by issue ID
    • Alt-d - Return to default sort
    • Ctrl-h/j/k/l - Tmux pane navigation

Usage

gh-pm

The script will fetch up to 100 issues from your GitHub project and present them in an interactive fzf interface.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment