vig 0.13.0

Read-only TUI cockpit for busy repositories - git, GitHub PRs/CI/projects, containers and processes at a glance
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
# vig

[日本語](docs/README.ja.md)

A **read-only TUI cockpit** for busy repositories — git, GitHub issues / PRs /
CI runs / project boards, containers, processes and worktrees at a glance,
with vim-style keybindings. Built for keeping an eye on repos where the work
is happening — including ones where AI agents do it. (The name comes from
*vim* + *git*; everything stays rooted at the current repository.)

📖 **[User Guide](https://td72.github.io/vig/)** — installation, a tour of every view, the full configuration guide and reference, and troubleshooting *(also readable in-repo under [docs/guide/](docs/guide/src/SUMMARY.md))*

> **Safe by design** — vig only performs read operations and safe git commands (`git switch`, `git branch -d`). Destructive operations like merge, rebase, or force delete are intentionally excluded.

![demo](assets/demo.gif)

## Features

- Side-by-side diff view with syntax highlighting
- Branch selector with git log preview
- Compare working directory against any local branch
- Vim-style modes: Scroll, Normal, Visual, Visual-Line
- File tree with status indicators (A/D/M/R/?)
- Yank (copy) to system clipboard with vim motions
- Live file watching with auto-refresh
- Open files in external editor (`$EDITOR`)
- **GitHub View** — Browse Issues, Pull Requests (body, comments, reviews, CI status) and Actions workflow runs (jobs / steps, job logs) via `gh` CLI, read-only
- **Files View** — yazi-like three-column file browser (parent / current / preview) with syntax-highlighted previews
- **Docker View** — Containers grouped by compose project, images, inspect summary and a live log tail via the `docker` CLI (read-only)
- **Procs View** — read-only process tree with CPU / memory, listening ports and their owners, system CPU / memory history graphs and a per-process detail with CPU / RSS sparklines
- **Worktrees View** — git worktrees and stashes at a glance, with the HEAD commit or the stash diff (side-by-side) in a preview pane
- **Projects View** — the GitHub Projects (v2) boards linked to the repository: kanban columns by `Status`, a sortable table mode and an item detail with every project field, via the `gh` CLI (read-only)
- Configurable layout, key bindings, and highlighting theme via `~/.config/vig/config.kdl`

## Installation

### Homebrew

```bash
brew install td72/tap/vig
```

### Pre-built binaries

Download a pre-built binary from the [GitHub Releases](https://github.com/td72/vig/releases) page:

```bash
# Linux x86_64
curl -sL https://github.com/td72/vig/releases/latest/download/vig-x86_64-unknown-linux-gnu.tar.gz | tar xz -C ~/.local/bin vig

# Linux aarch64
curl -sL https://github.com/td72/vig/releases/latest/download/vig-aarch64-unknown-linux-gnu.tar.gz | tar xz -C ~/.local/bin vig

# macOS Apple Silicon
curl -sL https://github.com/td72/vig/releases/latest/download/vig-aarch64-apple-darwin.tar.gz | tar xz -C ~/.local/bin vig
```

### crates.io

```bash
cargo install vig
```

### Build from source

Requires: Rust toolchain, libgit2, libssl, pkg-config

```bash
cargo install --path .
```

## Usage

Run in a Git repository:

```bash
vig
```

## Configuration

vig works out of the box. To change something, drop a KDL file at
`~/.config/vig/config.kdl` — only the parts you write are overridden;
everything else keeps its default:

![config demo](assets/demo-config.gif)

```kdl
// ~/.config/vig/config.kdl
theme "Solarized (dark)"
page "git" {
    pane "file_tree" {
        keys {
            "o" "ExpandOrOpen"   // add a binding
        }
    }
}
```

```bash
vig config dump     # print the built-in defaults as a starting point
vig config path     # list the config layers (builtin / user / repo-local)
```

📖 Everything else — tabs, layouts, keybindings, per-repository `.vig.kdl`,
the full schema — lives in the User Guide:
**[Configuration Basics](https://td72.github.io/vig/configuration-basics.html)** ·
**[Config Recipes](https://td72.github.io/vig/config-recipes.html)** ·
**[Config Reference](https://td72.github.io/vig/config-reference.html)**

## Key Bindings

### View Switching

| Key | Action |
|-----|--------|
| `1` | Switch to Git View |
| `2` | Switch to GitHub View |
| `3` | Switch to Files View |
| `4` | Switch to Docker View |
| `5` | Switch to Procs View |
| `6` | Switch to Worktrees View |
| `7` | Switch to Projects View |

### Pane Navigation

| Key | Action |
|-----|--------|
| `Tab` / `Shift+Tab` | Cycle panes: Files → Branches → Reflog → GitLog → Diff |
| `h` / `l` | Move between adjacent upper panes (Files, Branches, Reflog) |
| `i` | Jump from upper pane to main pane (GitLog / Diff) |
| `Esc` | Return from main pane to previous upper pane |

### Navigation

| Key | Action |
|-----|--------|
| `j` / `k` | Scroll down / up |
| `h` / `l` | Scroll left / right (in Diff view) |
| `gg` | Jump to top |
| `G` | Jump to bottom |
| `Ctrl+d` / `Ctrl+u` | Half page down / up |

### Branch List

![branch demo](assets/demo-branch.gif)

| Key | Action |
|-----|--------|
| `j` / `k` | Navigate branches (git log preview updates) |
| `Enter` | Action menu (switch / delete / set as diff base) |
| `/` | Search branches |
| `Esc` | Clear search / Reset comparison to HEAD |

### Git Log

| Key | Action |
|-----|--------|
| `j` / `k` | Navigate commits |
| `Ctrl+d` / `Ctrl+u` | Half page scroll |
| `g` / `G` | Top / Bottom |
| `y` | Copy commit hash |
| `Y` | Copy commit URL |
| `o` | Open in GitHub |
| `/` | Search commits |
| `Esc` | Clear search / Back to Branch List |

### Reflog

| Key | Action |
|-----|--------|
| `j` / `k` | Navigate entries |
| `Ctrl+d` / `Ctrl+u` | Half page scroll |
| `g` / `G` | Top / Bottom |
| `Enter` | Set as diff base |
| `/` | Search reflog |
| `Esc` | Clear search / Back to Branches |

### Modes

| Key | Action |
|-----|--------|
| `i` | Enter Normal mode |
| `v` | Visual mode (character) |
| `V` | Visual-Line mode |
| `Esc` | Back to Scroll mode |

### Yank (copy)

![yank demo](assets/demo-yank.gif)

| Key | Action |
|-----|--------|
| `yy` | Yank line |
| `yw` / `ye` / `yb` | Yank word / end of word / word back |
| `y$` / `y0` | Yank to end / start of line |
| `y` (in Visual) | Yank selection |

Text objects are also supported: `iw`, `aw`, `i"`, `a"`, `i(`, `a(`, `i{`, `a{`

### Search

| Key | Action |
|-----|--------|
| `/` | Start search |
| `n` | Next match |
| `N` | Previous match |

Search works in all panes (DiffView, FileTree, CommitLog, Reflog). Case-insensitive.

### GitHub View

![github demo](assets/demo-github-pr.gif)

Browse GitHub Issues, Pull Requests and Actions workflow runs directly within vig. Requires [GitHub CLI (`gh`)](https://cli.github.com/) to be installed and authenticated.
Bodies and comments are rendered as Markdown (headings, lists, task lists, code, tables narrowed to fit the pane width where possible).
Sub-issues are listed under their parent issue as a tree, and PRs in a GitHub Stack (as created by [`gh stack`](https://github.com/github/gh-stack)) are nested bottom-to-top under the PR they build on.

The third column lists the latest 50 workflow runs (`gh run list`) with their
status, workflow, run number, branch, event, duration (elapsed while running)
and age; while any run is queued or in progress the list refreshes every 5
seconds (`github-poll-interval` in the config). Selecting a run fills the detail area with its jobs and their steps
nested underneath (failed steps in red) in the **Jobs** sub-pane; `Enter` on a
job or step loads that job's log into the **Log** sub-pane, with step
boundaries and `##[group]` markers rendered as section lines. Logs of jobs
that are still running are polled at the same interval and followed like a
tail. When GitHub rejects a request as rate-limited, the page suspends its
polling with an exponential backoff (30s up to 10 minutes) and shows
`⚠ GitHub rate limited (resets in Nm)` in the status bar; `r` retries
immediately and a successful fetch clears the backoff.
Nothing in this view reruns, cancels or deletes anything.

| Key | Action |
|-----|--------|
| `h` / `l` | Switch between the Issues, Pull Requests and Workflow Runs columns |
| `Tab` / `Shift+Tab` | Cycle the columns (in a detail view: its sub-panes) |
| `j` / `k` | Navigate list (the detail follows the selection) |
| `i` / `Enter` | Open detail view |
| `o` | Open in browser (issue, PR, run or the selected job) |
| `y` | Copy the item URL |
| `Esc` | Back to list |
| `h` / `l` (detail) | Body ↔ right-hand sub-panes; for a run: Jobs ↔ Log |
| `i` / `Enter` (run detail, Jobs) | Show the job's log (a step row scrolls to that step) |
| `]` / `[` (run detail) | Next / previous failed step in the log |
| `G` (run detail, Log) | Jump to the end and resume following |
| `/` `n` `N` | Search: `#number` / title, workflow / branch / event, or in a run detail the job and step names / log lines |
| `Ctrl+d` / `Ctrl+u` | Half page scroll (detail view) |
| `g` / `G` | Top / Bottom |
| `r` | Refresh data (in a detail view: only that item; a run re-fetches its jobs and log) |

### Files View

![files demo](assets/demo-files.gif)

A read-only file browser rooted at the repository. The left column shows the
parent directory, the middle the current one, and the right a preview of the
selected entry (syntax-highlighted text, or a listing for directories).
Entries get Nerd Font icons by file type; if your terminal font is not a
[Nerd Font](https://www.nerdfonts.com/), put `icons "none"` in your config.

Images (PNG / JPEG / GIF / WebP) are previewed in the pane, with their format,
dimensions, size and the renderer in use on the first line. In terminals with a graphics protocol
(Kitty, WezTerm, Ghostty, iTerm2, or Sixel-capable ones such as foot) the image
is drawn at full resolution; elsewhere it falls back to unicode half-blocks.
`image-preview "halfblocks"` skips the terminal detection and `"none"` shows
only the metadata. Images over 20 MB are not decoded.

Markdown files (`.md` / `.markdown`) are rendered in the preview — headings,
emphasis, lists, code and GFM tables fitted to the pane width. `m` toggles
back to the raw highlighted text, and `markdown-preview "raw"` makes raw the
default.

| Key | Action |
|-----|--------|
| `j` / `k` | Move selection (preview follows) |
| `l` / `` / `Enter` | Enter directory / focus preview |
| `h` / `` / `Backspace` | Parent directory |
| `i` | Focus preview |
| `j` / `k` / `Ctrl+d` / `Ctrl+u` (preview) | Scroll |
| `h` / `l` (preview) | Scroll long lines horizontally |
| `/` `n` `N` (preview) | Search the file contents (matches highlighted, view follows) |
| `Esc` (preview) | Clear the search / back to the file list |
| `/` `n` `N` | Search file names |
| `e` | Open selected file in external editor |
| `o` | Open selected file or directory with the OS default app (`open` / `xdg-open` / `explorer`) |
| `O` | Open selected entry with an app you name (`open -a <app>` on macOS) |
| `m` | Toggle Markdown rendering in the preview |
| `r` | Re-read the current directory |

### Docker View

![docker demo](assets/demo-docker.gif)

A read-only view of the local Docker daemon, built on the `docker` CLI's JSON
output (`docker ps`, `docker images`, `docker inspect`, `docker logs`). If
`docker` is not installed or the daemon is not running, the view shows a notice
instead of the panes. Containers are grouped under their compose project
(running ones first), the detail pane shows an inspect summary for the selected
container or image, and the logs pane tails the selected container
(`--tail 200`, then `--since` appends every second while following). The lists
refresh every 5 seconds. Environment variables are never displayed, and nothing
in this view starts, stops or removes anything.

| Key | Action |
|-----|--------|
| `j` / `k` | Move selection (detail and logs follow) |
| `i` / `Enter` | Focus the detail pane |
| `l` (containers) | Focus the logs pane |
| `Tab` / `Shift+Tab` | Cycle panes: Containers → Images → Detail → Logs |
| `j` / `k` / `Ctrl+d` / `Ctrl+u` (detail, logs) | Scroll (scrolling the logs pauses following) |
| `G` (logs) | Jump to the end and resume following |
| `/` `n` `N` | Search container / image names, or log lines |
| `h` / `Esc` (detail, logs) | Back to the list |
| `r` | Re-fetch containers, images, detail and logs |

### Procs View

![procs demo](assets/demo-procs.gif)

A read-only view of what is running: the processes as a tree by parent pid
with CPU % and resident memory, the listening TCP / UDP ports with the
process that owns each one, and a detail of the selected process (pid, ppid,
user, state, uptime, CPU / memory, full command line, cwd, executable,
children, listening ports). Values that need privileges you do not have are
shown as `(no access)`; environment variables are never read or displayed.
The view only inspects — it never sends a signal.

Processes come from [sysinfo](https://crates.io/crates/sysinfo); ports from
`lsof` on macOS and `ss` on Linux. Both are re-read every 2 seconds while the
view is shown (`procs-refresh-interval` in the config) and on `r`.

The System pane on top graphs the machine totals as btop-style filled area
charts: the global CPU % (with the recent peak) and the used memory over the
last `procs-history` samples (120 by default — 4 minutes at the 2 s
interval), plus a `Swp` line when swap is present. Every sample column is
colored by its load — green below 50 %, yellow from 50 %, red from 80 % —
and the percentage labels carry the same color. `c` swaps the CPU chart for
one small gauge per core in the same gradient. The charts fill from the
right until the buffer is full, sample while the view is shown, and always
cover the whole machine — they draw numbers only. The detail pane adds the
same history for the selected process: a colored CPU % area chart and a
resident-memory chart under the CPU / MEM fields.

| Key | Action |
|-----|--------|
| `j` / `k` / `Ctrl+d` / `Ctrl+u` / `g` / `G` | Move in the process tree (detail follows) |
| `s` | Cycle the sort: CPU → MEM → PID (shown in the pane title) |
| `c` | Toggle the CPU graph: history ⇄ one bar per core |
| `Enter` / `i` / `l` | Focus the detail pane |
| `/` `n` `N` | Search command lines (processes) or address / port / name (ports) |
| `Tab` / `Shift+Tab` | Cycle panes: Processes → Ports → Detail → System |
| `Enter` (ports) | Jump to the process that owns the port |
| `j` / `k` / `Ctrl+d` / `Ctrl+u` (detail) | Scroll |
| `h` / `Esc` (detail) | Back to the process list |
| `r` | Refresh now |

### Worktrees View

![worktrees demo](assets/demo-worktrees.gif)

A read-only overview of the repository's worktrees and stashes. The top-left
pane lists the worktrees (`git worktree list`) with their path — relative to
the main worktree where possible — the checked-out branch (or a detached
HEAD), and flags such as `[main]`, `[locked]`, `[prunable]` or `[bare]`; the
worktree vig is running in is marked with `*`. The bottom-left pane lists the
stashes (`stash@{n}`, message, the branch they were made on and how long ago).

The preview on the right follows the selection: for a worktree it shows the
HEAD commit (hash, author, date, subject) and its changed files; for a stash
it shows the stash's patch, including untracked files it carries, in the same
side-by-side diff view as the Git view — syntax highlighting, search, and
Normal / Visual mode with yank work there. Nothing is ever applied,
dropped, added or removed from this view.

| Key | Action |
|-----|--------|
| `Tab` / `Shift+Tab` | Cycle panes: Worktrees → Stashes → Preview |
| `j` / `k` | Move selection (preview follows) |
| `i` / `l` / `Enter` | Focus the preview |
| `j` / `k` / `Ctrl+d` / `Ctrl+u` (preview) | Scroll |
| `h` / `l` (preview) | Scroll the diff horizontally |
| `[` / `]` (preview) | Previous / next file in a multi-file stash |
| `i` (preview) | Normal mode in the stash diff (`v` / `V` / `y` as in the Git view) |
| `Esc` / `Backspace` (preview) | Back to the list |
| `/` `n` `N` | Search paths / branches (worktrees), messages / branches (stashes), or the diff |
| `r` | Re-read worktrees and stashes |

### Projects View

![projects demo](assets/demo-projects.gif)

A read-only board for the GitHub Projects (v2) linked to the current
repository (`gh repo view --json projectsV2`), with the board itself fetched over GraphQL (a few points per board). The board takes the
full width and the first linked project shows up right away: one column per
`Status` option in GitHub's order, plus a `No status` column for items
without one. With several linked projects the header reads
`Board: <title> (i/n)` and `p` / `P` cycle through them; with none the
board explains how to link one (the repository's Projects tab or
`gh project link`). A top-level `projects-board` config node pins the page
to one board, by title or project number
([Config Reference](https://td72.github.io/vig/config-reference.html#projects-board)). Cards show the item type (`●` issue, `⇅` pull request,
`✎` draft), number, title and assignees; a card whose item lives in another
repository carries a dimmed `owner/repo` prefix before its number. `t`
switches to a table with one row per item and the project's fields (Status,
Priority, Estimate, Iteration, dates, custom text / number fields) as
sortable columns. The detail pane lists every field value of the selected
item, then the issue / PR body and comments as in the GitHub view (drafts
show their body). Past 500 items the status bar says `(truncated)`.

A `projects` list pane also exists but is not placed by the built-in
layout. Placing it in your config gets a selectable list of the linked
projects back — see the
[guide's recipe](https://td72.github.io/vig/config-recipes.html#bring-the-projects-list-pane-back)
for the layout to paste.

`gh project` needs the `project` token scope. When it is missing the view
shows a notice instead of the panes: run `gh auth refresh -s project`, then
press `r`. Nothing in this view adds, moves, edits or deletes anything.

| Key | Action |
|-----|--------|
| `p` / `P` | Next / previous linked project |
| `h` / `l`, `` / `` (board) | Previous / next column (table mode: sort column) |
| `j` / `k` (board) | Move between cards in a column (table mode: rows) |
| `t` (board) | Toggle table mode |
| `s` (board, table mode) | Cycle the sort column |
| `Enter` / `i` (board) | Focus the detail |
| `v` / `V` | Next / previous saved view of the project |
| `Space` | Collapse / expand the selected swimlane (grouped board views) |
| `+` / `-` | Zoom the roadmap time scale in / out |
| `o` | Open the project / item in the browser |
| `y` | Copy the project / item URL |
| `j` / `k` / `Ctrl+d` / `Ctrl+u` (detail) | Scroll |
| `h` / `Esc` (detail) | Back to the board |
| `Tab` / `Shift+Tab` | Cycle panes: Board → Detail |
| `/` `n` `N` | Search item titles / numbers across columns |
| `r` | Re-read the linked projects, the board and the shown item |

### Other

| Key | Action |
|-----|--------|
| `Enter` / `Space` | Open file / Toggle directory |
| `e` | Open in external editor |
| `r` | Refresh diff and branches |
| `?` | Show help |
| `q` / `Ctrl+c` | Quit |

## Development

### Setup

```bash
mise install   # installs prek
mise exec -- prek install   # installs pre-commit hooks
```

### Pre-commit hooks

Managed by [prek](https://github.com/j178/prek):

- `cargo fmt --check`
- `cargo clippy`
- Trailing whitespace, EOF fixer, TOML/YAML check, merge conflict check, large file check
- GIF freshness check (tape modified → gif must be re-recorded)

### CI

GitHub Actions runs on push to `main` and pull requests:

- prek hooks (fmt + clippy)
- `cargo test`
- `cargo build`

## License

MIT