- Go 96.2%
- Shell 3.3%
- PowerShell 0.4%
- Makefile 0.1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
|
||
| .claude | ||
| .forgejo | ||
| cmd/lazyforge | ||
| docs | ||
| internal | ||
| scripts | ||
| .gitignore | ||
| .golangci.yml | ||
| CLAUDE.md | ||
| go.mod | ||
| go.sum | ||
| install.ps1 | ||
| install.sh | ||
| LICENSE | ||
| Makefile | ||
| README.md | ||
| renovate.json | ||
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.
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.
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:
- Choosing Forgejo, Gitea, GitHub or GitLab and entering your server address (pre-filled with
https://github.comfor GitHub andhttps://gitlab.comfor GitLab). - Pasting an access token or supplying a command that prints one, then testing the connection.
- 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 hideN, 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
- Design: UI model, navigation, keymap and Renovate features
- Architecture: core/adapter split, domain model, host config and API mapping
- Interactive mockup: design reference; open in a browser and use vim keys
- Decision records: why the big technical calls were made
- Agent guide: ticket, review and MR workflow
License
MIT.

