Keyboard-driven TUI for git forges (Forgejo, Gitea, GitHub, GitLab) with first-class Renovate support
  • Go 96.2%
  • Shell 3.3%
  • PowerShell 0.4%
  • Makefile 0.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Bob Parsons 310d28d93d
All checks were successful
github-push / push (push) Successful in 6s
ci / check (push) Successful in 1m10s
feat(gitlab): run Renovate now on GitLab
Reviewed-on: ⁨#151⁩
2026-10-12 11:17:42 -05:00
.claude docs: trim the agent guide and product-voice skill 2026-10-09 10:52:03 -05:00
.forgejo feat(release): mirror releases to GitHub and fall back to it 2026-10-09 17:29:19 -05:00
cmd/lazyforge feat(ui): connect to GitLab from onboarding and the host picker (#146) 2026-10-12 08:47:31 -05:00
docs feat(gitlab): run Renovate now on GitLab 2026-10-12 11:17:42 -05:00
internal feat(gitlab): run Renovate now on GitLab 2026-10-12 11:17:42 -05:00
scripts feat(release): mirror releases to GitHub and fall back to it 2026-10-09 17:29:19 -05:00
.gitignore feat(core): cache, background refresh and stale-result protection (#28) 2026-10-02 12:35:40 -05:00
.golangci.yml feat(github): add the GitHub adapter's client and core methods (#88) 2026-10-09 09:54:05 -05:00
CLAUDE.md docs: trim the agent guide and product-voice skill 2026-10-09 10:52:03 -05:00
go.mod fix(deps): update module golang.org/x/mod to v0.42.0 2026-10-10 08:32:56 -05:00
go.sum fix(deps): update module golang.org/x/mod to v0.42.0 2026-10-10 08:32:56 -05:00
install.ps1 feat(release): mirror releases to GitHub and fall back to it 2026-10-09 17:29:19 -05:00
install.sh feat(release): mirror releases to GitHub and fall back to it 2026-10-09 17:29:19 -05:00
LICENSE chore: add MIT licence and scrub personal data from test fixtures 2026-10-04 16:06:18 -05:00
Makefile feat(release): support Windows 2026-10-09 12:02:09 -05:00
README.md feat(gitlab): run Renovate now on GitLab 2026-10-12 11:17:42 -05:00
renovate.json chore(ci): cache Go and pinned tools, single release build (#67) 2026-10-08 22:09:45 -05:00

lazyforge

A keyboard-driven terminal UI for your git forge: pull requests, issues, Actions, releases and Renovate, with vim keys throughout.

lazygit handles the git side of your work. lazyforge handles the forge side: everything that lives on the server.

Status: v1 supports Forgejo, Gitea, GitHub (github.com or GitHub Enterprise Server) and GitLab (gitlab.com or self-managed). Prebuilt binaries for Linux, macOS and Windows (Intel and ARM), or build from source.

lazyforge demo showing pull requests, issues, Actions and a PR overview

What it does

  • Browse repositories in columns, then step into pull requests, issues, Actions, Renovate updates and releases.
  • Read PR and issue bodies, diffs and comments; merge or approve PRs, close items, edit labels and post comments.
  • Inspect CI runs and job logs, and open run pages in your browser.
  • Use the cross-repo ★ Renovate view to group updates by dependency, inspect failing CI, merge updates across repositories and tick Dependency Dashboard entries.
  • Configure multiple hosts and connect to one per session.

Install

Linux and macOS, on Intel or ARM. This downloads the latest release, checks its checksum and installs lazyforge to ~/.local/bin:

curl -fsSL https://git.bobparsons.dev/deadstyle/lazyforge/raw/branch/main/install.sh | bash

Make sure ~/.local/bin is on your PATH. Set LAZYFORGE_INSTALL_DIR to install elsewhere, or LAZYFORGE_VERSION (for example v0.1.0) to pick a release. Once installed, lazyforge offers newer releases at launch and updates itself. If the Forgejo server is unreachable, installs and updates fall back to the GitHub mirror of the releases.

Windows, on Intel or ARM, from PowerShell:

irm https://git.bobparsons.dev/deadstyle/lazyforge/raw/branch/main/install.ps1 | iex

This installs lazyforge.exe to %LOCALAPPDATA%\Programs\lazyforge and adds that folder to your user PATH. Set LAZYFORGE_INSTALL_DIR to install elsewhere, or LAZYFORGE_VERSION to pick a release.

Install from source

Requires Git, Go 1.27.2 or newer (the version in go.mod), and make.

git clone https://git.bobparsons.dev/deadstyle/lazyforge.git
cd lazyforge
make build
./bin/lazyforge -demo

The binary is bin/lazyforge. To put it on your PATH:

mkdir -p ~/.local/bin
install -m 0755 bin/lazyforge ~/.local/bin/lazyforge

Make sure ~/.local/bin is on your PATH, then run lazyforge from any directory.

Try the demo

lazyforge -demo

Demo mode uses built-in sample repositories, PRs, issues, CI runs and releases. It needs no account, token or config and does not connect to a forge. Merge, approve, close and dashboard actions update the in-memory demo data; restart to reset it. Browser actions still open the sample URLs.

lazyforge demo showing the cross-repository Renovate overview and grouped dependency updates

Both screenshots show the running demo at 140×34 terminal cells. Start on ★ Renovate, or press j to select homelab and l to explore its PRs.

Connect your forge

Run lazyforge without -demo. With no config file, first-run onboarding walks you through:

  1. Choosing Forgejo, Gitea, GitHub or GitLab and entering your server address (pre-filled with https://github.com for GitHub and https://gitlab.com for GitLab).
  2. Pasting an access token or supplying a command that prints one, then testing the connection.
  3. Setting the Renovate bot username (leave blank to skip), an optional Renovate workflow as owner/repo/file, or the Renovate project's path on GitLab (leave blank to hide N, which runs Renovate now), and a short host name.

On Forgejo or Gitea, create a token at your server's /user/settings/applications page with read:user, write:repository and write:issue, as shown in onboarding. These cover sign-in, repositories, PRs, CI, issues and the actions above.

On GitHub, create a token at /settings/tokens: a classic token with the repo scope, or a fine-grained token with Contents, Pull requests and Issues read/write plus Actions, Checks and Commit statuses read. gh auth token works as the token command.

On GitLab, create a personal access token at /-/user_settings/personal_access_tokens with the api scope (read_api is not enough). glab auth token works as the token command.

Onboarding saves config.toml with mode 0600. On Linux the default path is ~/.config/lazyforge/config.toml; on macOS it is ~/Library/Application Support/lazyforge/config.toml. XDG_CONFIG_HOME overrides the base directory on either platform. A pasted token is stored in that file; a token command is stored instead when you choose that option.

Press S for settings to add or edit hosts. To select a configured host or use another config file:

lazyforge -host home
lazyforge -config /path/to/config.toml

Use lazyforge -help for all flags, -version to print the build version, or -no-update-check to skip the startup release check.

Run Renovate now (optional)

If Renovate runs as a workflow on your forge, set renovate_workflow = "owner/repo/file.yml" on the host (or set it in Settings under Renovate, or in the Renovate step of onboarding or host edit). N then starts that workflow on its repo's default branch. You need write access to that repo, and on GitHub a token that can write Actions. Leave it unset to hide N.

A run for all repos sends no inputs, so any workflow_dispatch workflow works for that. A run for one repo sends an input named repo with the value owner/name, so the workflow has to declare it and pass it to Renovate as RENOVATE_AUTODISCOVER_FILTER. GitHub rejects inputs a workflow doesn't declare, so without this the one-repo choice fails with the forge's message.

on:
  schedule:
    - cron: "0 8 * * *"
  workflow_dispatch:
    inputs:
      repo:
        description: "Limit the run to one repo (owner/name). Empty runs every repo."
        required: false
        default: ""

jobs:
  renovate:
    runs-on: ubuntu-latest
    steps:
      - name: Run Renovate
        env:
          ONLY_REPO: ${{ inputs.repo }}
        run: |
          if [ -n "$ONLY_REPO" ]; then
            export RENOVATE_AUTODISCOVER_FILTER="$ONLY_REPO"
          fi
          renovate

The snippet shows only the parts N relies on; keep your own container image, token and RENOVATE_* settings.

On GitLab, set renovate_workflow to the path of the project that runs Renovate, for example renovate_workflow = "group/renovate-runner". N then runs that project's pipeline on its default branch. You need Developer access or higher on that project, and a token with the api scope. A run for one repo sets the CI variable RENOVATE_AUTODISCOVER_FILTER to group/project, which Renovate reads from the environment, so the pipeline needs no change. The pipeline's rules must allow a pipeline started through the API ($CI_PIPELINE_SOURCE == "api"); otherwise GitLab refuses and lazyforge shows its message.

Keys

Key Action
j / k, ↓ / ↑ Move through a list
l / h, → / ← Enter / go back
1–5 Jump to a numbered box
Tab / Shift+Tab Next / previous box
[ / ] Switch detail tabs
Space Mark an item for a bulk action
r Refresh
S Settings (connected mode)
? Show the full, context-sensitive keymap
q Quit

Available actions and their keys appear in the footer and help overlay.

Development

In addition to Go and make, make check requires golangci-lint v2 and ShellCheck. CI pins their versions in the setup action.

make check   # format check, lint, race-enabled tests, vulnerability scan, build, installer checks
make run     # build and start the app

License

MIT.