gh-source v2

July 15, 2026 ยท View on GitHub

gh-source v2 is a small Zsh-only GitHub plugin loader focused on fast startup and readable declarations.

It clones missing repositories, detects existing regular or nested-worktree checkouts, performs declarative setup, and sources plugins in the active shell.

Install

brew install yarden-zamir/tap/gh-source

Use the fixed path printed by brew info gh-source rather than running brew --prefix during every shell startup:

source /opt/homebrew/opt/gh-source/share/gh-source/gh-source.zsh

Only the gh_source function is provided.

Source Plugins

gh_source hlissner/zsh-autopair/autopair.zsh

The path shorthand equals an explicit source action:

gh_source hlissner/zsh-autopair --source autopair.zsh

Additional sources run in declaration order:

gh_source junegunn/fzf/shell/completion.zsh \
  --path bin \
  --preserve-zsh-options \
  --source shell/key-bindings.zsh

--preserve-zsh-options runs sources in Zsh's native LOCAL_OPTIONS scope. It prevents option changes from leaking on success or failure and hides $options for scripts such as fzf that try to restore the immutable zle option. Ordinary calls do not inspect or restore options.

With no explicit source, gh_source owner/repo checks the resolved checkout root for:

<repo>.plugin.zsh
<repo>.zsh
init.zsh

Files under scripts/ or other directories require an explicit path.

PATH And Completions

gh_source owner/tool --path bin
gh_source owner/completions --fpath zsh

--path appends to PATH. --fpath prepends to fpath. Both resolve relative to the selected checkout and avoid duplicate entries.

Conditional Builds

gh_source Yarden-zamir/navgator/scripts/navgator.zsh \
  --skip-build-if-present navgator \
  --skip-build-if-present target/release/navgator \
  --build cargo build --release

Each predicate first checks for a regular file under the checkout, then calls command -v with the same value. Any match skips the build.

--build must be final. Its argv runs directly in a subshell rooted at the checkout. Build commands receive:

GH_SOURCE_DIR
GH_SOURCE_REPO
GH_SOURCE_REPO_NAME

A successful build must make at least one predicate true.

Repository Layout

Repositories default to:

$GH_SOURCE_ROOT/<repo>

GH_SOURCE_ROOT defaults to $HOME/Github.

Missing repositories always clone normally. Existing worktree containers resolve automatically through .bare/HEAD, with main/ as fallback.

To convert a cloned repository to the nested layout, use dedicated worktree tooling:

"$DOTFILES/bin/wt-migrate" --yes "$HOME/Github/<repo>"

The next gh_source call automatically uses the primary worktree. gh-source does not create _shared/, convert repositories, or select arbitrary worktrees.

State And Updates

gh_source --loaded owner/repo
gh_source --loaded owner/repo/file.zsh
gh_source --list
gh_source --update

Sources load once per shell. Only complete successful activations are registered.

Updates deduplicate resolved roots, refuse dirty repositories, and run git pull --ff-only. They never reset or discard changes.

Source Semantics

Sources see caller Zsh options. Option changes persist unless --preserve-zsh-options is present.

Zsh treats plain typeset inside any function as local; plugins must use assignment or typeset -g for persistent globals.

Parameter names beginning with _ghs_ are reserved for loader internals while sources run.

If sourcing fails, PATH, fpath, and effects from any started source cannot be rolled back.

Development

uv run tests/test_gh_source.py
uvx ruff check tests/test_gh_source.py
zsh -n gh-source.zsh

The complete v2 behavior contract is in docs/specs/v2.md. Migration notes are in PLUGIN_LOADING_BEHAVIOR.md.