# Claude Code Instructions for lazygitclj

## Clojure Development

- Use Clojure skills (nREPL evaluation) when editing code to verify changes compile and work correctly
- Evaluate code in the REPL to test functions before committing changes
- Run `bb start` to launch the application, `bb test` for unit tests

## Local TUI Library

- The TUI library is at `../clojure-tui/` (local dependency in bb.edn)
- You have access to edit the local TUI library in conjunction with this repo
- Use this access to debug issues, support new features, and simplify code
- Look for opportunities to create better abstraction primitives for TUI layout

## Testing with VHS

- Use VHS to test all changes and verify behavior before finishing any task
- Run `bb test:e2e` to run VHS tape tests
- Run VHS tape files to capture terminal recordings and validate UI behavior
- Do not consider a task complete until changes have been verified with VHS

## Understanding Expected Behavior

- Reference the lazygit repository and documentation to understand expected behaviors
- Use VHS locally with lazygit to compare and verify that lazygitclj matches expected interaction patterns
- When implementing features, check how lazygit handles the same functionality
- See `PRD.md` for detailed lazygit behavior documentation

---

## Project Overview

lazygitclj is a lazygit-inspired TUI for Git written in Clojure, targeting Babashka for fast startup. It follows the Elm Architecture pattern (Model-Update-View).

## Project Structure

```
src/lazygitclj/
├── core.clj          # Main TUI app: views, update logic, keybindings (883 lines)
├── git.clj           # Git operations wrapper via shell commands (478 lines)
└── debug_tui.clj     # Layout debugging utility
test/
├── lazygitclj/
│   ├── core_test.clj # Model/update function tests
│   └── git_test.clj  # Git operations tests (uses temp repo fixture)
└── run-tests.clj     # Test runner
```

## Build Commands

| Command | Purpose |
|---------|---------|
| `bb start` | Run lazygitclj TUI |
| `bb debug` | Debug TUI layout issues |
| `bb test` | Run unit tests |
| `bb test:e2e` | Run VHS tape tests |

## Architecture: Elm Pattern

```clojure
(tui/run {:init (initial-model)
          :update update-model
          :view view})
```

- **Model**: Application state as a map
- **Update**: Pure functions returning `[new-model command]` tuples
- **View**: Pure functions rendering hiccup-style VDom

## Model Structure

```clojure
{:panel :files              ;; Current panel: :files, :branches, :commits, :stash
 :cursor 0                  ;; Cursor position in current panel
 :message nil               ;; Transient message display
 :input-mode nil            ;; :commit, :new-branch, :rename-branch, etc.
 :input-buffer ""           ;; Text input during modal entry
 :menu-mode nil             ;; :stash-options, :reset-options, :help
 :commits-tab :commits      ;; :commits or :reflog
 :branches-tab :local       ;; :local, :remotes, or :tags
 :branch "main"             ;; Current branch
 :sha "abc1234"             ;; HEAD SHA
 :ahead-behind [0 0]        ;; [ahead, behind] upstream
 :staged [...]              ;; Staged files
 :unstaged [...]            ;; Unstaged/untracked files
 :commits [...]             ;; Recent commits
 :branches [...]            ;; Local branches
 :remote-branches [...]     ;; Remote branches
 :tags [...]                ;; Tags
 :stashes [...]             ;; Stash entries
 :reflog [...]              ;; Reflog for undo/redo
 :diff nil}                 ;; Currently displayed diff
```

## Key Functions in core.clj

| Function | Purpose |
|----------|---------|
| `initial-model` | Create initial application state |
| `load-git-data` | Load all git state via git.clj |
| `refresh` | Reload git data and update diff |
| `update-model` | Main dispatcher for keyboard input |
| `update-files` | Handle files panel (stage, unstage, commit) |
| `update-commits` | Handle commits panel (checkout, cherry-pick, revert) |
| `update-branches` | Handle branches panel (checkout, create, delete, merge) |
| `update-stash` | Handle stash panel (apply, pop, drop) |
| `file-items` | Combine staged/unstaged files with type metadata |
| `current-items` | Get items for current panel |
| `view` | Render UI based on state and dimensions |

## Keybindings

**Global**: `q` quit, `?` help, `r` refresh, `h/l` panel nav, `j/k` cursor, `z/Z` undo/redo, `p/P` pull/push, `D` reset menu

**Files**: `space` stage/unstage, `a` stage all, `c` commit, `d` discard, `s/S` stash

**Commits**: `space` checkout, `g` reset to, `C` cherry-pick, `t` revert, `r` reword, `[/]` tabs

**Branches**: `enter` checkout, `n` new, `d` delete, `R` rename, `M` merge, `f` fast-forward, `[/]` tabs

**Stash**: `space` apply, `g` pop, `d` drop, `n` branch from stash

## Git Operations (git.clj)

All git operations wrap `babashka.process/shell` and return `nil` on error.

**Categories**:
- Status: `current-branch`, `head-sha`, `ahead-behind`
- Files: `status-files`, `staged-files`, `unstaged-files`
- Staging: `stage-file`, `unstage-file`, `stage-all`
- Diff: `diff-file`, `diff-staged`, `show-commit`, `diff-branch`
- Actions: `commit`, `discard-file`, `pull`, `push`
- Stash: `stash-list`, `stash-push`, `stash-pop`, `stash-apply`, `stash-drop`
- Reset: `reset-soft`, `reset-mixed`, `reset-hard`
- Branches: `create-branch`, `checkout-branch`, `delete-branch`, `merge-branch`
- Tags: `list-tags`, `create-tag`, `delete-tag`

## TUI Library Primitives

```clojure
;; Containers
[:row {:widths [30 :flex] :gap 1} left right]
[:col {:heights [3 :flex :flex 4]} top mid1 mid2 bottom]
[:box {:border :double :title "Title"} content]

;; Text with styling
[:text {:fg :green :bold true} "content"]
```

- `:flex` keyword items share remaining space equally
- Borders: `:single`, `:double`, `:rounded`
- Colors: `:red`, `:green`, `:yellow`, `:blue`, `:magenta`, `:cyan`, `:white`

## Responsive Layout

- **Narrow (< 70 cols)**: Single-column stacked layout
- **Wide (>= 70 cols)**: Two-column (left panels 30 cols, right diff flex)

## File Status Format

Files parsed from `git status --porcelain`:
```clojure
{:index \M :worktree \space :path "file.txt"}
```

## Diff Coloring

- `+` lines: green (additions)
- `-` lines: red (deletions)
- `@@` lines: cyan (hunk headers)
- `diff`/`commit` lines: yellow (headers)

## Conventions

- Predicates end with `?` (e.g., `can-fast-forward?`)
- Private functions prefixed with `-` (e.g., `-sh`, `-parse-status-line`)
- Update functions return `[new-model command]` tuples
- Messages are transient (cleared on next refresh)
