define a legible :Forge master workflow around root + local git pickers #87

Closed
opened 2026-04-07 17:09:35 +00:00 by barrettruth · 0 comments
barrettruth commented 2026-04-07 17:09:35 +00:00

Canonical issue

This is the canonical issue for the :Forge master workflow / home-surface lane.

It supersedes the earlier rougher threads in:

  • #59 master picker
  • #79 scope a picker-agnostic master workflow for :Forge

It is adjacent to, but intentionally separate from:

  • #63 closer git integration/pr viewer

#63 is specifically about first-class PR review. This issue is about the :Forge entry point itself and the local git workflows surfaced there, especially branches, commits, and worktrees.

Thesis

forge.nvim should treat :Forge as a legible workflow surface, not just a route dispatcher.

Today the plugin already has the pieces for a strong top-level git + forge workflow, but the current presentation does not make that clear. The practical result is that the user can open :Forge, see Issues, Branches, Commits, and Worktrees, and still not really understand:

  • what each section actually opens
  • what the primary action inside each picker is
  • whether the section is forge-backed, git-backed, or mixed
  • what commands the section shells out to
  • what abstractions are truly picker-agnostic vs backend-specific

That makes the top-level workflow feel thinner and more accidental than it really is.

Philosophy

1. Legibility at the point of entry

The root :Forge picker should communicate intent before the user opens a nested picker.

A user should not need to inspect source, help docs, or trial-and-error keypresses to understand what Branches, Commits, and Worktrees are for.

2. Local git workflows are first-class, not filler

branches, commits, and worktrees should feel like core parts of forge.nvim's workflow model, not just incidental utility lists attached to a forge plugin.

If forge.nvim is a “forge-agnostic git workflow for Neovim”, then local git views belong near the center of the product story.

3. Picker backend should be an implementation detail

Users should not have to mentally model fzf-lua vs snacks vs telescope just to understand the workflow. Backend differences matter, but the conceptual workflow should be stable across them.

4. Shell-outs should be discoverable, not magical

The plugin should not feel like a black box. It is good for advanced users to be able to answer:

  • what command does this picker run?
  • what command does this action run?
  • which parts are plain git vs forge CLI?

That does not necessarily mean every command must be shown in the UI, but the mapping should exist somewhere explicit.

5. Do not jump to a bespoke picker before the design pressure is real

A first-party picker or UI may eventually be the right move, but the immediate problem is not “we need our own picker tech.”

The immediate problem is that the existing workflow is under-explained and under-shaped at the top, while local git sections are lighter than the more mature PR/issue/CI flows.

Verified current architecture

The current flow is roughly:

  1. plugin/forge.lua defines :Forge and the <Plug> launchers
  2. require('forge').open() resolves into lua/forge/routes.lua
  3. routes.open() either:
    • opens the root picker, or
    • resolves a named route and dispatches to a handler
  4. the root picker is built from section aliases and route handlers
  5. nested pickers are implemented in lua/forge/pickers.lua
  6. picker rendering is delegated to one of:
    • lua/forge/picker/fzf.lua
    • lua/forge/picker/snacks.lua
    • lua/forge/picker/telescope.lua

Important structural detail:

  • the root menu uses the client abstraction (lua/forge/client.lua)
  • nested pickers go directly through the picker abstraction (lua/forge/picker/init.lua)

So there is already a seam for a richer top-level workflow, but it currently only exists at the root.

Verified default root model

Current root section order:

  • prs
  • issues
  • ci
  • branches
  • commits
  • worktrees
  • browse
  • releases

Current default route aliases:

  • prs -> prs.open
  • issues -> issues.open
  • ci -> ci.current_branch
  • browse -> browse.contextual
  • releases -> releases.all
  • branches -> branches.local
  • commits -> commits.current_branch
  • worktrees -> worktrees.list

At the moment, the root entries are essentially plain labels.

That means the root is functionally a route launcher more than a workflow surface.

Verified command surface

For a GitHub repository like this one, the current implementation shells out to commands such as:

Context and detection

  • git rev-parse --show-toplevel
  • git branch --show-current
  • git rev-parse HEAD
  • git remote get-url origin

Issues

  • gh issue list --limit <n> --state <state> --json ...

PRs

  • gh pr list --limit <n> --state <state> --json ...

Branches

List:

  • git for-each-ref --format=... refs/heads

Actions:

  • git switch <branch>
  • browse branch via forge when available

Commits

List:

  • git log --max-count=100 --format=... <branch>

Actions:

  • git show --stat --patch --decorate=short <sha>
  • browse commit via forge when available

Worktrees

List:

  • git worktree list --porcelain

Actions:

  • switch Neovim cwd to the selected worktree
  • copy the worktree path

PR worktree creation

  • git fetch origin pull/<num>/head:pr-<num>
  • git worktree add ../pr-<num> pr-<num>

Equivalent forge-specific command implementations also exist for GitLab (glab) and Codeberg/Gitea/Forgejo (tea).

Verified backend support

Current built-in picker backends:

  • fzf-lua
  • snacks.nvim
  • telescope.nvim

All three currently support the essentials needed for this workflow work:

  • segmented row rendering
  • row highlighting
  • action bindings
  • non-closing actions
  • root and nested picker usage

Notable differences today:

  • fzf-lua has the richest header/action-hint treatment
  • snacks and telescope preserve highlighted rows but do not get the same header UX
  • there is a public root client extension point, but not an equivalent public picker-backend registration API

The real problem statement

The core problem is not just that the root picker is visually sparse.

The deeper problem is that the current workflow does not sufficiently explain itself.

Symptoms

  • The root picker does not tell the user what each section actually does
  • The local git sections are useful but feel visually lighter than PR/issue/CI
  • There is no single explicit route -> command -> action inventory
  • The existence of both client and picker abstractions is not reflected in the UX or documentation story
  • It is unclear whether “master picker” means:
    • a richer root launcher
    • a more coherent picker-agnostic workflow layer
    • or a future first-party UI

Resulting user confusion

A user can reasonably ask:

  • “Are branches, commits, and worktrees actually core to the intended workflow?”
  • “What exactly does this picker shell out to?”
  • “What do the underlying pickers support?”
  • “Do we just need to polish these pickers, or are we supposed to be inventing a new system?”

That is the confusion this issue should resolve.

What the first concrete implementation should actually be

The first implementation milestone should not be “build a whole new picker system.”

The first real milestone should be:

  1. make the root :Forge picker legible
  2. do a serious polish pass on:
    • branches
    • commits
    • worktrees
  3. document the route -> command -> action story
  4. document backend capability differences in one place

That is the smallest change set that actually answers the product question.

What “make the root legible” means

It means that from the root picker alone, the user should be able to infer what opening a section will do.

Instead of plain entries like:

  • Branches
  • Commits
  • Worktrees

we should be able to render richer backend-agnostic entries such as:

  • Branches
    local refs · git switch · browse branch
  • Commits
    current branch history · git show · browse commit
  • Worktrees
    repo worktrees · switch cwd · copy path

This can be done with segmented display data and existing highlight groups; no picker backend rewrite is required to start here.

Proposed UX scope

Root :Forge picker

Goals:

  • add secondary descriptive text to entries
  • visually distinguish local git sections from forge-backed sections where helpful
  • make section purpose visible without requiring entry
  • preserve route alias behavior and picker backend portability

Potential data points for each root entry:

  • label
  • short description
  • route target
  • scope hint (e.g. current branch, all issues, local refs)
  • category hint (forge, git, mixed)

This does not require exposing raw shell commands in the root list, but the displayed copy should make the workflow obvious.

Branches picker

Goals:

  • strengthen current branch emphasis
  • make the default action clearer
  • improve readability of upstream / sha / tip summary
  • make the picker feel explicitly like a local git workflow with optional forge browse

Potential improvements:

  • better segmented layout and highlighting
  • clearer current-marker treatment
  • more deliberate prompt/header language
  • stronger empty state copy

Commits picker

Goals:

  • strengthen SHA / subject / author / age hierarchy
  • make it obvious that the list is scoped to a branch
  • make git show feel intentional rather than incidental

Potential improvements:

  • stronger visual distinction for SHA
  • better branch context in the prompt
  • clearer action naming and description

Worktrees picker

Goals:

  • make branch-backed worktrees easier to scan
  • make detached / bare states visually obvious
  • make the “switch cwd” intent clearer

Potential improvements:

  • stronger labeling of current vs detached worktrees
  • clearer path/branch hierarchy
  • more explicit prompt and action copy

Proposed deliverables

  • design note for the :Forge master workflow
  • richer root entries with descriptive secondary text
  • visual polish pass on branches / commits / worktrees
  • explicit route -> command -> action inventory
  • backend capability matrix for fzf-lua, snacks, and telescope
  • recommendation on whether to keep extending the current abstraction or move toward a first-party workflow surface
## Canonical issue This is the canonical issue for the `:Forge` master workflow / home-surface lane. It supersedes the earlier rougher threads in: - #59 `master picker` - #79 `scope a picker-agnostic master workflow for :Forge` It is adjacent to, but intentionally separate from: - #63 `closer git integration/pr viewer` #63 is specifically about first-class PR review. This issue is about the `:Forge` entry point itself and the local git workflows surfaced there, especially `branches`, `commits`, and `worktrees`. ## Thesis `forge.nvim` should treat `:Forge` as a legible workflow surface, not just a route dispatcher. Today the plugin already has the pieces for a strong top-level git + forge workflow, but the current presentation does not make that clear. The practical result is that the user can open `:Forge`, see `Issues`, `Branches`, `Commits`, and `Worktrees`, and still not really understand: - what each section actually opens - what the primary action inside each picker is - whether the section is forge-backed, git-backed, or mixed - what commands the section shells out to - what abstractions are truly picker-agnostic vs backend-specific That makes the top-level workflow feel thinner and more accidental than it really is. ## Philosophy ### 1. Legibility at the point of entry The root `:Forge` picker should communicate intent before the user opens a nested picker. A user should not need to inspect source, help docs, or trial-and-error keypresses to understand what `Branches`, `Commits`, and `Worktrees` are for. ### 2. Local git workflows are first-class, not filler `branches`, `commits`, and `worktrees` should feel like core parts of forge.nvim's workflow model, not just incidental utility lists attached to a forge plugin. If forge.nvim is a “forge-agnostic git workflow for Neovim”, then local git views belong near the center of the product story. ### 3. Picker backend should be an implementation detail Users should not have to mentally model `fzf-lua` vs `snacks` vs `telescope` just to understand the workflow. Backend differences matter, but the conceptual workflow should be stable across them. ### 4. Shell-outs should be discoverable, not magical The plugin should not feel like a black box. It is good for advanced users to be able to answer: - what command does this picker run? - what command does this action run? - which parts are plain git vs forge CLI? That does not necessarily mean every command must be shown in the UI, but the mapping should exist somewhere explicit. ### 5. Do not jump to a bespoke picker before the design pressure is real A first-party picker or UI may eventually be the right move, but the immediate problem is not “we need our own picker tech.” The immediate problem is that the existing workflow is under-explained and under-shaped at the top, while local git sections are lighter than the more mature PR/issue/CI flows. ## Verified current architecture The current flow is roughly: 1. `plugin/forge.lua` defines `:Forge` and the `<Plug>` launchers 2. `require('forge').open()` resolves into `lua/forge/routes.lua` 3. `routes.open()` either: - opens the root picker, or - resolves a named route and dispatches to a handler 4. the root picker is built from section aliases and route handlers 5. nested pickers are implemented in `lua/forge/pickers.lua` 6. picker rendering is delegated to one of: - `lua/forge/picker/fzf.lua` - `lua/forge/picker/snacks.lua` - `lua/forge/picker/telescope.lua` Important structural detail: - the root menu uses the `client` abstraction (`lua/forge/client.lua`) - nested pickers go directly through the `picker` abstraction (`lua/forge/picker/init.lua`) So there is already a seam for a richer top-level workflow, but it currently only exists at the root. ## Verified default root model Current root section order: - `prs` - `issues` - `ci` - `branches` - `commits` - `worktrees` - `browse` - `releases` Current default route aliases: - `prs` -> `prs.open` - `issues` -> `issues.open` - `ci` -> `ci.current_branch` - `browse` -> `browse.contextual` - `releases` -> `releases.all` - `branches` -> `branches.local` - `commits` -> `commits.current_branch` - `worktrees` -> `worktrees.list` At the moment, the root entries are essentially plain labels. That means the root is functionally a route launcher more than a workflow surface. ## Verified command surface For a GitHub repository like this one, the current implementation shells out to commands such as: ### Context and detection - `git rev-parse --show-toplevel` - `git branch --show-current` - `git rev-parse HEAD` - `git remote get-url origin` ### Issues - `gh issue list --limit <n> --state <state> --json ...` ### PRs - `gh pr list --limit <n> --state <state> --json ...` ### Branches List: - `git for-each-ref --format=... refs/heads` Actions: - `git switch <branch>` - browse branch via forge when available ### Commits List: - `git log --max-count=100 --format=... <branch>` Actions: - `git show --stat --patch --decorate=short <sha>` - browse commit via forge when available ### Worktrees List: - `git worktree list --porcelain` Actions: - switch Neovim cwd to the selected worktree - copy the worktree path ### PR worktree creation - `git fetch origin pull/<num>/head:pr-<num>` - `git worktree add ../pr-<num> pr-<num>` Equivalent forge-specific command implementations also exist for GitLab (`glab`) and Codeberg/Gitea/Forgejo (`tea`). ## Verified backend support Current built-in picker backends: - `fzf-lua` - `snacks.nvim` - `telescope.nvim` All three currently support the essentials needed for this workflow work: - segmented row rendering - row highlighting - action bindings - non-closing actions - root and nested picker usage Notable differences today: - `fzf-lua` has the richest header/action-hint treatment - `snacks` and `telescope` preserve highlighted rows but do not get the same header UX - there is a public root `client` extension point, but not an equivalent public picker-backend registration API ## The real problem statement The core problem is not just that the root picker is visually sparse. The deeper problem is that the current workflow does not sufficiently explain itself. ### Symptoms - The root picker does not tell the user what each section actually does - The local git sections are useful but feel visually lighter than PR/issue/CI - There is no single explicit route -> command -> action inventory - The existence of both `client` and `picker` abstractions is not reflected in the UX or documentation story - It is unclear whether “master picker” means: - a richer root launcher - a more coherent picker-agnostic workflow layer - or a future first-party UI ### Resulting user confusion A user can reasonably ask: - “Are branches, commits, and worktrees actually core to the intended workflow?” - “What exactly does this picker shell out to?” - “What do the underlying pickers support?” - “Do we just need to polish these pickers, or are we supposed to be inventing a new system?” That is the confusion this issue should resolve. ## What the first concrete implementation should actually be The first implementation milestone should **not** be “build a whole new picker system.” The first real milestone should be: 1. make the root `:Forge` picker legible 2. do a serious polish pass on: - `branches` - `commits` - `worktrees` 3. document the route -> command -> action story 4. document backend capability differences in one place That is the smallest change set that actually answers the product question. ## What “make the root legible” means It means that from the root picker alone, the user should be able to infer what opening a section will do. Instead of plain entries like: - `Branches` - `Commits` - `Worktrees` we should be able to render richer backend-agnostic entries such as: - `Branches` `local refs · git switch · browse branch` - `Commits` `current branch history · git show · browse commit` - `Worktrees` `repo worktrees · switch cwd · copy path` This can be done with segmented display data and existing highlight groups; no picker backend rewrite is required to start here. ## Proposed UX scope ### Root `:Forge` picker Goals: - add secondary descriptive text to entries - visually distinguish local git sections from forge-backed sections where helpful - make section purpose visible without requiring entry - preserve route alias behavior and picker backend portability Potential data points for each root entry: - label - short description - route target - scope hint (e.g. current branch, all issues, local refs) - category hint (forge, git, mixed) This does **not** require exposing raw shell commands in the root list, but the displayed copy should make the workflow obvious. ### Branches picker Goals: - strengthen current branch emphasis - make the default action clearer - improve readability of upstream / sha / tip summary - make the picker feel explicitly like a local git workflow with optional forge browse Potential improvements: - better segmented layout and highlighting - clearer current-marker treatment - more deliberate prompt/header language - stronger empty state copy ### Commits picker Goals: - strengthen SHA / subject / author / age hierarchy - make it obvious that the list is scoped to a branch - make `git show` feel intentional rather than incidental Potential improvements: - stronger visual distinction for SHA - better branch context in the prompt - clearer action naming and description ### Worktrees picker Goals: - make branch-backed worktrees easier to scan - make detached / bare states visually obvious - make the “switch cwd” intent clearer Potential improvements: - stronger labeling of current vs detached worktrees - clearer path/branch hierarchy - more explicit prompt and action copy ## Proposed deliverables - [ ] design note for the `:Forge` master workflow - [ ] richer root entries with descriptive secondary text - [ ] visual polish pass on branches / commits / worktrees - [ ] explicit route -> command -> action inventory - [ ] backend capability matrix for `fzf-lua`, `snacks`, and `telescope` - [ ] recommendation on whether to keep extending the current abstraction or move toward a first-party workflow surface
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
barrettruth/forge.nvim#87
No description provided.