# AGENTS.md - tuicr
This document serves two purposes:
1. Help coding agents understand the tuicr codebase structure
2. Explain how to interpret review feedback generated by tuicr
---
## Project Structure
tuicr is a Rust terminal UI application for code reviews. Here's the module structure:
```
src/
├── main.rs # Entry point, event loop, action dispatch
├── config/
│ └── mod.rs # User config loading (XDG on Unix, %APPDATA% on Windows)
├── app.rs # Application state (App struct, InputMode, etc.)
├── error.rs # Error types (TuicrError enum)
├── tuicrignore.rs # .tuicrignore loader + diff file filtering (gitignore-style patterns)
├── theme/
│ └── mod.rs # Theme palette definitions + CLI theme parsing/resolution
│
├── vcs/ # VCS abstraction layer
│ ├── mod.rs # detect_vcs(): auto-detect VCS (jj first, then git, then hg)
│ ├── traits.rs # VcsBackend trait, VcsInfo, VcsType, CommitInfo
│ ├── diff_parser.rs # Unified diff text parser (shared by hg/jj)
│ │ # DiffFormat enum: Hg (with timestamps), GitStyle (jj/git patches)
│ ├── git/ # Git backend (uses native git2 library, not diff_parser)
│ │ ├── mod.rs # GitBackend: wraps git2 library
│ │ ├── repository.rs # CommitInfo, get_recent_commits()
│ │ ├── diff.rs # get_working_tree_diff(), get_commit_range_diff()
│ │ └── context.rs # fetch_context_lines() for gap expansion
│ ├── hg/ # Mercurial backend (always compiled)
│ │ └── mod.rs # HgBackend: uses hg CLI, parses with diff_parser::Hg
│ └── jj/ # Jujutsu backend (always compiled)
│ └── mod.rs # JjBackend: uses jj CLI, parses with diff_parser::GitStyle
│
├── model/
│ ├── mod.rs
│ ├── comment.rs # Comment, CommentType (Note/Suggestion/Issue/Praise)
│ ├── diff_types.rs # DiffFile, DiffHunk, DiffLine, FileStatus, LineOrigin
│ └── review.rs # ReviewSession, FileReview (the persisted review state)
│
├── input/
│ ├── mod.rs
│ ├── keybindings.rs # Action enum, map_key_to_action() for each InputMode
│ └── mode.rs # InputMode enum definition (unused, defined in app.rs)
│
├── persistence/
│ ├── mod.rs
│ └── storage.rs # save_session, load_session, find_session_for_repo
│
├── output/
│ ├── mod.rs
│ └── markdown.rs # export_to_clipboard(): generate markdown, copy to clipboard
│
└── ui/
├── mod.rs
├── app_layout.rs # Main render function, file list, diff view with inline comments
├── status_bar.rs # Header, status bar, command line rendering
├── help_popup.rs # Help overlay (? key)
├── comment_panel.rs # Comment input dialog, confirm dialog
└── styles.rs # Color constants and style helper functions
```
Repository-managed agent integrations:
- `skills/tuicr/` - Shared agent skill bundle for coding agents, for example Claude Code, Codex, and similar tools; launches tuicr in a tmux split pane
### Key Types
**App** (`src/app.rs`):
- Central application state
- Contains: `vcs` (Box<dyn VcsBackend>), `vcs_info`, `session`, `diff_files`, `input_mode`, scroll/cursor state
- Methods: `scroll_down/up`, `next/prev_file`, `next/prev_hunk`, `go_to_source_line`, `toggle_reviewed`, `save_comment`
**VcsBackend** (`src/vcs/traits.rs`):
- Trait abstracting VCS operations
- Methods: `info()`, `get_working_tree_diff()`, `fetch_context_lines()`, `get_recent_commits()`, `get_commit_range_diff()`
- Implementations: `GitBackend`, `HgBackend`, `JjBackend` (all always compiled)
**InputMode** (`src/app.rs`):
- `Normal` - default navigation mode
- `Command` - after pressing `:`, vim-style commands
- `Comment` - typing a comment (Ctrl-S saves, Ctrl-C cancels)
- `Search` - after pressing `/`, search pattern entry
- `Help` - showing help popup
- `Confirm` - Y/N confirmation dialog
- `CommitSelect` - selecting commits to review
- `VisualSelect` - visual mode for range comments
**ReviewSession** (`src/model/review.rs`):
- Persisted review state with `files: HashMap<PathBuf, FileReview>`
- Each `FileReview` has: `reviewed: bool`, `file_comments: Vec<Comment>`, `line_comments: HashMap<u32, Vec<Comment>>`
**Action** (`src/input/keybindings.rs`):
- All possible user actions (ScrollDown, NextFile, ToggleReviewed, AddLineComment, etc.)
- `map_key_to_action(key, mode)` returns the appropriate Action
### Data Flow
1. **Startup**: Parse CLI args (invalid `--theme` exits non-zero), load config from `$XDG_CONFIG_HOME/tuicr/config.toml` (default `~/.config/tuicr/config.toml`, or `%APPDATA%\tuicr\config.toml` on Windows), ignore unknown config keys with startup warnings, resolve theme precedence (`--theme` > config > dark), then call `App::new()`. `App::new()` calls `detect_vcs()` (Jujutsu first, then Git, then Mercurial), filters diff files via repo-root `.tuicrignore`, then enters commit selection mode by default. If staged/unstaged changes exist, the first selection rows are "Staged changes" and/or "Unstaged changes". With `-r/--revisions`, it opens the requested commit range directly. Config `show_file_list = false` hides the file list panel on startup (toggleable with `;e`). Config `diff_view = "side-by-side"` sets the default diff layout (toggleable with `:diff`). Config `wrap = true` enables line wrapping (toggleable with `:set wrap!`).
2. **Render**: `ui::render()` draws the TUI based on `App` state
3. **Input**: `crossterm` events → `map_key_to_action` → match on Action in main loop
4. **Persistence**: `:w` calls `save_session()`, writes JSON to `~/.local/share/tuicr/reviews/`
5. **Reload diff**: `:e` re-runs VCS diff loading and reapplies `.tuicrignore` filtering to refresh displayed files
6. **Export**: `:clip` (alias `:export`) calls `export_to_clipboard()`, generating markdown and copying it to the clipboard (or stdout with `--stdout` flag)
### Important Implementation Details
- **Infinite scroll**: All files rendered into one `Vec<Line>`, then sliced by `scroll_offset`
- **Inline comments**: Comments are rendered in `app_layout.rs` after file headers and after relevant diff lines
- **Session loading**: `App::new()` calls `find_session_for_repo()` to restore previous review
- **Clipboard**: Uses `arboard` crate for cross-platform clipboard support
- **Hunk navigation**: `next_hunk()`/`prev_hunk()` calculate positions by iterating through files
- **Ignore filtering**: `.tuicrignore` is applied whenever diffs are loaded/reloaded
### Dependencies
- `ratatui` + `crossterm`: TUI framework
- `git2`: Native git operations
- `serde` + `serde_json`: Session serialization
- `toml`: User config parsing
- `arboard`: Clipboard access
- `ignore`: Gitignore-style matcher for `.tuicrignore`
- `chrono`: Timestamps
- `thiserror` + `anyhow`: Error handling
### Keeping Docs Updated
When adding user-facing features, update the relevant documentation:
| Document | Update when adding/changing... |
|----------|-------------------------------|
| `README.md` | Keybindings, commands (`:*`), CLI flags, features list, installation methods, agent integration setup |
| `src/ui/help_popup.rs` | Keybindings or commands (update the `help_text` vector) |
| `AGENTS.md` | Module structure, repo-managed agent integrations, key types, data flow, dependencies |
---
## Review Format (for coding agents receiving tuicr output)
When a user reviews your changes with tuicr, they will provide you with a structured Markdown document optimized for agent consumption.
### Document Structure
```markdown
I reviewed your code and have the following comments. Please address them.
Comment types: ISSUE (problems to fix), SUGGESTION (improvements), NOTE (observations), PRAISE (positive feedback)
Summary: {optional overall notes}
1. **[ISSUE]** `src/auth.rs:42` - Magic number should be a named constant
2. **[SUGGESTION]** `src/api.rs` - Consider adding unit tests
3. **[NOTE]** `src/utils.rs:15` - Why was this approach chosen?
```
### Comment Types
| Type | Meaning | Action Required |
|------|---------|-----------------|
| **[ISSUE]** | Problem that must be fixed | Yes - address before proceeding |
| **[SUGGESTION]** | Improvement recommendation | Consider implementing |
| **[NOTE]** | Observation or question | Respond or acknowledge |
| **[PRAISE]** | Positive feedback | No action needed |
### Comment Format
Each comment is numbered and self-contained:
- `{n}. **[TYPE]** \`{file}:{line}\` - {content}` (line comment)
- `{n}. **[TYPE]** \`{file}\` - {content}` (file comment)
You can reference comments by number (e.g., "Regarding comment #2...").
### How to Respond
#### 1. Address Issues First
**[ISSUE]** comments are blocking and must be fixed:
```markdown
## Issues Addressed
- #1 `src/auth.rs:42` - Extracted magic number to `TOKEN_EXPIRY_SECONDS` constant
```
#### 2. Consider Suggestions
**[SUGGESTION]** comments are non-blocking but should be considered. Either implement or explain why not.
#### 3. Answer Questions
**[NOTE]** comments often contain questions. Provide brief explanations.
### Response Format
```markdown
## Changes Made
### Issues Addressed
- #1 - Extracted magic number to `TOKEN_EXPIRY_SECONDS` constant
### Suggestions Implemented
- #2 - Added unit tests for API module
### Suggestions Declined
- #5 - Kept current approach because [reason]
### Notes Addressed
- #3 - This approach was chosen for performance reasons
```
## Tips for Coding Agents
1. **Read the full review** before making changes
2. **Prioritize [ISSUE] items** - these are blocking
3. **Reference comments by number** when responding
4. **Preserve reviewer intent** - don't over-engineer solutions
5. **Be concise** in your response
6. **If unclear**, ask for clarification rather than guessing