···11+# jj_tui - Interactive Rebase Preview
22+33+## What This Is
44+55+A terminal UI for Jujutsu (jj) version control that provides visual, interactive rebase previews. Users can see exactly how their commit graph will look after a rebase before executing the operation, making rebasing safer and more intuitive.
66+77+## Core Value
88+99+Visual rebase preview with live graph updates - users must be able to configure a rebase interactively, see the resulting graph structure with preview nodes, and execute only when they're confident the result is correct.
1010+1111+## Requirements
1212+1313+### Validated
1414+1515+<!-- Existing capabilities confirmed from codebase -->
1616+1717+- ✓ TUI commit graph visualization with Nottui/Notty/Lwd - existing
1818+- ✓ JJ CLI subprocess execution and output parsing - existing
1919+- ✓ Reactive UI state management via Lwd.var - existing
2020+- ✓ Multi-node selection with space key - existing
2121+- ✓ Graph navigation (up/down/scroll) - existing
2222+- ✓ Custom graph renderer (static display working) - existing
2323+- ✓ Rebase command variants (single/children/branch) - existing
2424+- ✓ Command keybinding system with mode support - existing
2525+- ✓ Functor-based modular architecture - existing
2626+2727+### Active
2828+2929+<!-- Current scope: Interactive rebase preview feature -->
3030+3131+- [ ] Rebase mode activation (press 'r' on hovered commit)
3232+- [ ] Destination selection (space-select target nodes while in rebase mode)
3333+- [ ] Source mode toggle (press 's': single/children/branch)
3434+- [ ] Destination mode toggle (press 'd': insert-before/insert-after/add-after)
3535+- [ ] Preview node insertion into graph data structure
3636+- [ ] Preview node rendering (distinct color + symbol)
3737+- [ ] Dynamic graph re-rendering on mode/selection changes
3838+- [ ] Cycle detection (prevent commit being ancestor + descendant)
3939+- [ ] UI mode indicators (show current source and destination modes)
4040+- [ ] Rebase execution on confirmation (press 'y')
4141+- [ ] Cancel and exit rebase mode (press 'esc')
4242+4343+### Out of Scope
4444+4545+- Multiple simultaneous rebases (treating multi-select as separate operations) - complexity not needed for MVP
4646+- Other preview modes (squash, split, parallelize) - future enhancement
4747+- Performance optimization for large graphs - premature until rebase preview works
4848+- Undo/redo within rebase preview mode - JJ has `jj undo` at CLI level
4949+- Persistent rebase state across sessions - ephemeral mode is sufficient
5050+5151+## Context
5252+5353+**Codebase Architecture:**
5454+- OCaml 5.2+ functional reactive TUI
5555+- Nottui/Notty for terminal rendering, Lwd for reactive state
5656+- Picos for structured concurrency
5757+- Custom graph renderer in `render_jj_graph.ml` (1,117 lines, lane-based algorithm)
5858+- Command system in `graph_commands.ml` with 547 lines of existing commands
5959+- Global reactive state in `global_vars.ml` (ui_state_t, graph state)
6060+6161+**Graph Rendering:**
6262+- Custom renderer implemented and working for static display
6363+- Renders commit graph with Unicode box-drawing glyphs
6464+- Lane-based algorithm handles node positioning and parent-child relationships
6565+- Golden tests verify exact glyph output
6666+6767+**Rebase Command Structure:**
6868+- Three source modes: single revision (`-r`), with descendants (`-s`), bookmark (`-b`)
6969+- Destination specified via `-d` flag
7070+- Insert modes: `--insert-before`, `--insert-after`, or default (add as parent)
7171+- Existing commands at lines 312-342 in `graph_commands.ml`
7272+7373+**Technical Debt to Navigate:**
7474+- Frame rendering delay (TODO in `global_funcs.ml:46`)
7575+- Unsafe list access patterns in graph rendering
7676+- No tests for command execution logic
7777+7878+**Known Constraints:**
7979+- Must integrate with existing JJ CLI (no direct repo access)
8080+- Graph structure from JJ must be augmented, not replaced
8181+- Preview nodes need clear visual distinction to avoid confusion
8282+8383+## Constraints
8484+8585+- **Language**: OCaml 5.2+ - existing codebase
8686+- **TUI Framework**: Nottui/Notty/Lwd - forked versions maintained in `forks/`
8787+- **VCS Integration**: JJ CLI subprocess execution only - no direct libgit2/jj library access
8888+- **Architecture**: Functor-based with reactive state - must maintain existing patterns
8989+- **Build System**: Dune 3.12+ - established build configuration
9090+- **Testing**: ppx_expect inline tests - existing test infrastructure
9191+9292+## Key Decisions
9393+9494+| Decision | Rationale | Outcome |
9595+|----------|-----------|---------|
9696+| Custom graph renderer over jj's ASCII output | Need dynamic preview node insertion and re-rendering | ✓ Good - static rendering complete |
9797+| Hovered node as rebase source, space-select for destinations | Consistent with existing selection model, clear intent | — Pending |
9898+| Single rebase at a time (ignore multi-select) | Simpler state management, clearer preview | — Pending |
9999+| Mode toggles with 'd'/'s' keys | Quick iteration without prompts, shows all options | — Pending |
100100+| Distinct preview node rendering (color + symbol) | Must be unmistakably different from real commits | — Pending |
101101+| Cycle detection before preview | Prevent invalid graph states, better UX than error on execute | — Pending |
102102+103103+---
104104+*Last updated: 2026-01-15 after initialization*
+173
.planning/codebase/ARCHITECTURE.md
···11+# Architecture
22+33+**Analysis Date:** 2026-01-15
44+55+## Pattern Overview
66+77+**Overall:** Functional Reactive TUI Application with Structured Concurrency
88+99+**Key Characteristics:**
1010+- Single native executable with reactive UI
1111+- Functor-based modular architecture
1212+- Structured concurrency via Picos multi-domain parallelism
1313+- Reactive data flow using Lwd
1414+1515+## Layers
1616+1717+**UI/Presentation Layer:**
1818+- Purpose: Terminal rendering and user interaction
1919+- Contains: View implementations, widget composition, rendering logic
2020+- Key modules:
2121+ - `jj_tui/bin/jj_ui.ml` - Main UI orchestrator
2222+ - `jj_tui/bin/graph_view.ml` - Commit graph visualization
2323+ - `jj_tui/bin/file_view.ml` - File explorer and modification pane
2424+ - `jj_tui/bin/show_view.ml` - Details/preview pane
2525+ - `jj_tui/lib/commit_render.ml` - Commit rendering with syntax highlighting
2626+- Depends on: Notty, Nottui, Lwd, global state
2727+- Used by: Main entry point
2828+2929+**Command/Input Layer:**
3030+- Purpose: Handle user input and map to actions
3131+- Contains: Command definitions, keybinding system, input handlers
3232+- Key modules:
3333+ - `jj_tui/bin/graph_commands.ml` - Graph view commands (552 lines)
3434+ - `jj_tui/bin/file_commands.ml` - File view commands
3535+ - `jj_tui/bin/jj_commands.ml` - Core command execution framework (512 lines)
3636+ - `jj_tui/lib/key_map.ml` - Flexible keybinding system (405 lines)
3737+- Depends on: Global state, JJ process layer
3838+- Used by: View implementations
3939+4040+**State Management Layer:**
4141+- Purpose: Reactive application state
4242+- Contains: Lwd.var-based state store
4343+- Key modules:
4444+ - `jj_tui/bin/global_vars.ml` - Central reactive state (ui_state_t, graph state)
4545+ - `jj_tui/bin/global_funcs.ml` - State manipulation utilities
4646+- Depends on: Lwd reactive primitives
4747+- Used by: All layers
4848+4949+**Process Execution Layer:**
5050+- Purpose: Execute JJ CLI and parse output
5151+- Contains: Process spawning, output parsing, JJ integration
5252+- Key modules:
5353+ - `jj_tui/bin/jj_process.ml` - Mutex-protected JJ CLI execution (375 lines)
5454+ - `jj_tui/lib/process_wrappers.ml` - JJ output parsing (336 lines)
5555+ - `jj_tui/lib/jj_json.ml` - JSON/JSONL parsing from jj log
5656+- Depends on: Picos_io for async I/O
5757+- Used by: Command layer
5858+5959+**Data Processing Layer:**
6060+- Purpose: Parse and render JJ data structures
6161+- Contains: Graph rendering algorithm, ANSI parsing
6262+- Key modules:
6363+ - `jj_tui/lib/render_jj_graph.ml` - Lane-based graph rendering (1,117 lines)
6464+ - `jj_tui/lib/ansiReverse.ml` - ANSI escape code handling (337 lines)
6565+ - `jj_tui/lib/outputParsing.ml` - JJ output utilities
6666+- Depends on: Parsing libraries (angstrom, re)
6767+- Used by: UI layer
6868+6969+**Configuration Layer:**
7070+- Purpose: Load and manage user preferences
7171+- Contains: Config loading, logging setup
7272+- Key modules:
7373+ - `jj_tui/lib/config.ml` - YAML config loading
7474+ - `jj_tui/lib/logging.ml` - Structured logging
7575+ - `jj_tui/lib/os.ml` - OS detection
7676+- Depends on: Yaml, logs libraries
7777+- Used by: All layers
7878+7979+## Data Flow
8080+8181+**User Input Flow:**
8282+8383+1. User presses key in terminal
8484+2. `jj_tui/bin/main.ml` - Nottui event loop captures input
8585+3. `jj_tui/bin/jj_ui.ml` - UI forwards event to active view
8686+4. Command lookup via `key_map` registry
8787+5. Command builder in `graph_commands.ml` or `file_commands.ml` constructs command variant
8888+6. `jj_tui/bin/jj_commands.ml` - `run_command` executes command
8989+7. `jj_tui/bin/jj_process.ml` - JJ CLI execution (mutex-protected)
9090+8. Output parsing via `jj_json.ml` or `process_wrappers.ml`
9191+9. State update via `Lwd.set` in `global_vars.ml`
9292+10. Reactive re-render: `render_jj_graph.ml` + `commit_render.ml`
9393+11. Display to terminal via Notty
9494+9595+**Command Execution Lifecycle:**
9696+9797+```
9898+Key press → Command resolution → Command variant construction →
9999+Async execution (Cmd_async) or Synchronous (Cmd) →
100100+JJ process spawn → Output capture → State update → UI re-render
101101+```
102102+103103+**State Management:**
104104+- All state stored as `Lwd.var` reactive variables
105105+- Changes trigger automatic UI updates
106106+- Global mutex prevents concurrent JJ CLI access
107107+108108+## Key Abstractions
109109+110110+**Functors (Dependency Injection):**
111111+- Purpose: Modular architecture with testability
112112+- Pattern: `module Make (Vars : Global_vars.Vars)`
113113+- Examples:
114114+ - `Jj_ui.Make(Vars)` - `jj_tui/bin/jj_ui.ml`
115115+ - `Graph_view.Make(Vars)`, `File_view.Make(Vars)` - View implementations
116116+ - `Jj_process.Make(Vars)` - Process execution
117117+ - `Graph_commands.Make(Vars)`, `File_commands.Make(Vars)` - Command definitions
118118+119119+**Command Variants:**
120120+- Purpose: Flexible command system supporting various execution patterns
121121+- Examples: `Cmd`, `Cmd_r`, `Dynamic_r`, `PromptThen`, `Selection_prompt`, `Cmd_async`, `SubCmd`
122122+- Pattern: Variant types with lazy evaluation and composition
123123+124124+**Reactive Variables (Lwd.var):**
125125+- Purpose: State management with automatic propagation
126126+- Examples: `hovered_revision`, `graph_revs`, `ui_state`, `term_width_height`
127127+- Pattern: `let$` syntax sugar for reactive bindings
128128+129129+**Process Safety:**
130130+- Purpose: Prevent concurrent JJ CLI access
131131+- Pattern: Global mutex `Jj_process.access_lock` in `jj_tui/bin/jj_process.ml`
132132+- Concurrency: Picos structured concurrency with Flock task management
133133+134134+## Entry Points
135135+136136+**Main Executable:**
137137+- Location: `jj_tui/bin/main.ml` (88 lines)
138138+- Triggers: User runs `jj_tui` command
139139+- Responsibilities: Initialize 4 Picos domains, setup logging, launch TUI event loop
140140+141141+**UI Orchestrator:**
142142+- Location: `jj_tui/bin/jj_ui.ml` (261 lines)
143143+- Triggers: Called by main after initialization
144144+- Responsibilities: Bind views together, forward events, manage popups
145145+146146+## Error Handling
147147+148148+**Strategy:** Exception-based with Result types for parsing
149149+150150+**Patterns:**
151151+- Process errors: Captured and logged, UI shows error messages
152152+- Parse errors: Result types propagate failures to UI
153153+- Unsafe operations: Some intentional `failwith` for programmer errors
154154+155155+## Cross-Cutting Concerns
156156+157157+**Logging:**
158158+- File-based logging via `logs` library - `jj_tui/lib/logging.ml`
159159+- Mutex-protected for thread safety
160160+- Platform-specific log directories
161161+162162+**Validation:**
163163+- YAML schema validation for config - `jj_tui/lib/config.ml`
164164+- Key binding validation - `jj_tui/lib/key.ml`
165165+166166+**Concurrency:**
167167+- Picos structured concurrency - 4 domains launched in `jj_tui/bin/main.ml`
168168+- Global mutex for JJ CLI access - `jj_tui/bin/jj_process.ml`
169169+170170+---
171171+172172+*Architecture analysis: 2026-01-15*
173173+*Update when major patterns change*
+176
.planning/codebase/CONCERNS.md
···11+# Codebase Concerns
22+33+**Analysis Date:** 2026-01-15
44+55+## Tech Debt
66+77+**Rendering delay (performance):**
88+- Issue: UI always renders "at least one frame behind" user input
99+- Files: `jj_tui/bin/global_funcs.ml:46` (TODO comment)
1010+- Why: Current reactive variable update pattern introduces frame delay
1111+- Impact: Slight UI lag, user perceives delayed response
1212+- Fix approach: Mailbox processor pattern to trigger updates without Lwd.var delay
1313+1414+**Double rendering requirement:**
1515+- Issue: Some UI updates require double render pass for correct display
1616+- Files: `jj_tui/bin/graph_view.ml:137` (TODO comment)
1717+- Why: Dependency on layout calculations from previous frame
1818+- Impact: Slight performance overhead, extra frame delay
1919+- Fix approach: Refactor rendering to compute layout in single pass
2020+2121+**DOP list duplication:**
2222+- Issue: "Stop using dop last twice" - code duplication in list processing
2323+- Files: `jj_tui/bin/global_funcs.ml:61` (TODO comment)
2424+- Why: Quick implementation without refactoring
2525+- Impact: Redundant computation, harder to maintain
2626+- Fix approach: Extract shared logic into helper function
2727+2828+**Commented-out code:**
2929+- Issue: Large blocks of old implementation left in comments
3030+- Files: `jj_tui/bin/jj_process.ml:57-110` (picos_process old implementation)
3131+- Why: Historical reference during refactoring
3232+- Impact: Code clutter, confusion for new contributors
3333+- Fix approach: Remove commented code, rely on git history
3434+3535+## Known Bugs
3636+3737+**No known critical bugs documented**
3838+- No explicit bug tracking in code comments
3939+- No FIXME comments found
4040+- TODO items represent planned improvements, not bugs
4141+4242+## Security Considerations
4343+4444+**Shell command execution (low risk):**
4545+- Risk: JJ CLI executed with user-provided arguments
4646+- Files: `jj_tui/bin/jj_process.ml`
4747+- Current mitigation: Arguments come from UI state, not direct user input
4848+- Recommendations: Input validation already adequate for TUI context
4949+5050+**Build-time shell substitution:**
5151+- Risk: Shell command in dune build rule with environment variable
5252+- Files: `jj_tui/bin/dune:40-42` (GIT_DESCRIBE substitution)
5353+- Current mitigation: Build-time only, not runtime
5454+- Recommendations: Low priority - build environment trusted
5555+5656+**Unsafe operations:**
5757+- Risk: `unsafe_color_of_int`, `unsafe_style_of_int` could crash on invalid input
5858+- Files: `jj_tui/lib/ansiReverse.ml:9-11,14-15,142,164`
5959+- Current mitigation: Input validated by ANSI parser before unsafe ops
6060+- Recommendations: Add defensive checks or document preconditions
6161+6262+## Performance Bottlenecks
6363+6464+**Graph rendering complexity:**
6565+- Problem: Graph rendering algorithm is computationally intensive
6666+- Files: `jj_tui/lib/render_jj_graph.ml` (1,117 lines)
6767+- Measurement: No profiling data available
6868+- Cause: Lane-based algorithm with complex state tracking
6969+- Improvement path: Profile to identify hotspots, consider caching rendered glyphs
7070+7171+**String concatenation in loops:**
7272+- Problem: Inefficient string building during graph construction
7373+- Files: `jj_tui/lib/process_wrappers.ml:161`
7474+- Cause: Using `^` operator instead of Buffer
7575+- Improvement path: Replace with `Buffer.add_string` for better performance
7676+7777+**ANSI parsing on every render:**
7878+- Problem: Complex regex parsing runs on each frame
7979+- Files: `jj_tui/lib/ansiReverse.ml`
8080+- Cause: No caching of parsed ANSI sequences
8181+- Improvement path: Cache parsed output keyed by input string
8282+8383+## Fragile Areas
8484+8585+**Unsafe list access (high risk):**
8686+- Why fragile: `List.hd`, `List.nth` crash on empty/short lists
8787+- Files:
8888+ - `jj_tui/bin/graph_view.ml:68,87` - unchecked `List.nth`
8989+ - `jj_tui/lib/render_jj_graph.ml:525,1092` - `List.hd` without empty check
9090+ - Multiple test files use `List.hd` (acceptable in tests)
9191+- Common failures: Runtime exceptions on empty lists
9292+- Safe modification: Use pattern matching or `List.nth_opt`
9393+- Test coverage: No tests for edge cases (empty lists)
9494+9595+**Error escalation with failwith:**
9696+- Why fragile: Parsing errors converted to exceptions instead of Result propagation
9797+- Files:
9898+ - `jj_tui/lib/jj_json.ml:88` - failwith on JSON parse error
9999+ - `jj_tui/lib/process_wrappers.ml:63,72` - failwith for divergent parsing
100100+ - `jj_tui/lib/util.ml:54` - failwith for unicode validation
101101+- Common failures: Crashes on malformed JJ output
102102+- Safe modification: Return `Result.t` throughout parsing pipeline
103103+- Test coverage: Limited error case testing
104104+105105+**Mutable state in rendering:**
106106+- Why fragile: Multiple refs in graph rendering create complex state dependencies
107107+- Files: `jj_tui/lib/render_jj_graph.ml` (refs: `need_link_line`, `columns`, `result`, etc.)
108108+- Common failures: State inconsistencies if render order changes
109109+- Safe modification: Refactor to pure functional style with explicit state passing
110110+- Test coverage: Golden tests catch output changes but not state bugs
111111+112112+## Scaling Limits
113113+114114+**No explicit scaling limits identified**
115115+- Application is a local TUI tool, not a service
116116+- Performance scales with JJ repository size
117117+- Memory usage grows with commit graph size
118118+119119+## Dependencies at Risk
120120+121121+**ppx_record_updater (unmaintained fork):**
122122+- Risk: Pinned to personal fork `git+https://github.com/faldor20/ppx_record_updater.git`
123123+- Files: `dune-project`
124124+- Impact: Custom record update syntax used throughout (`[@updater]` attribute)
125125+- Migration plan: Monitor upstream, consider inlining if abandoned
126126+127127+**Forked UI libraries:**
128128+- Risk: Maintaining forks of nottui, notty, lwd
129129+- Files: `forks/nottui/`, `forks/notty/`, `forks/lwd/`
130130+- Impact: Need to track upstream changes, apply patches manually
131131+- Migration plan: Contribute patches upstream, reduce divergence
132132+133133+## Missing Critical Features
134134+135135+**No persistent state:**
136136+- Problem: No session persistence across restarts
137137+- Current workaround: Users restart from scratch each time
138138+- Blocks: Resuming work, saving UI preferences beyond config
139139+- Implementation complexity: Medium (add state serialization)
140140+141141+**No undo/redo:**
142142+- Problem: JJ operations cannot be undone from TUI
143143+- Current workaround: Use JJ CLI `jj undo` manually
144144+- Blocks: Safe experimentation with rebases/squashes
145145+- Implementation complexity: Medium (track command history)
146146+147147+## Test Coverage Gaps
148148+149149+**Command execution untested:**
150150+- What's not tested: Core command execution logic in `jj_commands.ml` (512 lines)
151151+- Risk: Commands could fail silently, incorrect JJ CLI invocation
152152+- Priority: High
153153+- Difficulty to test: Medium (need mock JJ CLI or integration tests)
154154+155155+**Process execution untested:**
156156+- What's not tested: JJ process spawning in `jj_process.ml` (375 lines)
157157+- Risk: Process management bugs, I/O handling failures
158158+- Priority: High
159159+- Difficulty to test: Medium (need process mocking)
160160+161161+**UI orchestration untested:**
162162+- What's not tested: Main UI logic in `jj_ui.ml` (261 lines)
163163+- Risk: Event routing bugs, view integration issues
164164+- Priority: Medium
165165+- Difficulty to test: High (requires TUI testing framework)
166166+167167+**State management untested:**
168168+- What's not tested: State updates in `global_funcs.ml`
169169+- Risk: State inconsistencies, race conditions
170170+- Priority: Medium
171171+- Difficulty to test: Medium (unit tests for state transitions)
172172+173173+---
174174+175175+*Concerns audit: 2026-01-15*
176176+*Update as issues are fixed or new ones discovered*
+133
.planning/codebase/CONVENTIONS.md
···11+# Coding Conventions
22+33+**Analysis Date:** 2026-01-15
44+55+## Naming Patterns
66+77+**Files:**
88+- snake_case for all source files (`commit_render.ml`, `jj_json.ml`, `render_jj_graph.ml`)
99+- Test files: `*_tests.ml` suffix (`commit_render_tests.ml`, `jj_json_tests.ml`)
1010+- Some camelCase preserved in library names (`ansiReverse.ml`, `outputParsing.ml`)
1111+1212+**Functions:**
1313+- snake_case for all functions (`render_commit_content`, `graph_node_attr`, `parse_jj_log_output`)
1414+- No special prefix for async functions
1515+- Event handlers: descriptive names (`forward_events`, `handle_input`)
1616+1717+**Variables:**
1818+- snake_case for variables (`hovered_revision`, `graph_revs`, `active_files`)
1919+- Constants: lowercase with underscores (`pad_amount = 2`)
2020+- Lwd reactive vars: descriptive names without special suffix
2121+2222+**Types:**
2323+- snake_case for type names (`ui_state_t`, `jj_commit`, `jj_author`, `command_variant`)
2424+- Variant constructors: PascalCase (`Cmd`, `Cmd_r`, `PromptThen`, `Selection_prompt`)
2525+- Record fields: snake_case (`working_copy`, `is_preview`, `change_id`)
2626+2727+## Code Style
2828+2929+**Formatting:**
3030+- OCamlformat with janestreet profile (`.ocamlformat`)
3131+- 2 space indentation
3232+- `let-binding-spacing=double-semicolon` - double semicolon termination
3333+- `space-around-records=true`, `space-around-lists=true`, `space-around-arrays=true`
3434+- `dock-collection-brackets=true` - collections start on new lines
3535+- `break-cases=nested` - match statements on multiple lines
3636+3737+**Linting:**
3838+- No explicit linting tool configured
3939+- Warnings enabled via dune (`-w A-4-42-44-45-48-66`)
4040+4141+## Import Organization
4242+4343+**Order:**
4444+1. External packages (Notty, Nottui, Lwd, Base, etc.)
4545+2. Local library modules (Jj_tui, Util, etc.)
4646+3. Functor modules (Make(Vars))
4747+4848+**Patterns:**
4949+- `open` statements at top of file or module
5050+- Selective opens: `open! Util` (force open even if shadowing)
5151+- Infix operators from Lwd: `open Lwd_infix`
5252+5353+**Path Aliases:**
5454+- None - uses explicit module paths
5555+5656+## Error Handling
5757+5858+**Patterns:**
5959+- Result types for parsing: `Result.t` with `Ok`/`Error`
6060+- Exceptions for programmer errors: `failwith` with descriptive messages
6161+- Graceful degradation: `Option.value ~default:...` for missing config
6262+6363+**Error Types:**
6464+- Parsing: Return `Result.t` with `Error (``Msg msg)`
6565+- Runtime: `failwith` for invariant violations
6666+- Unsafe operations: Deliberate `*_exn` suffix (e.g., `key_of_string_exn`)
6767+6868+## Logging
6969+7070+**Framework:**
7171+- `logs` library with custom file reporter (`jj_tui/lib/logging.ml`)
7272+- Levels: debug, info, warn, error
7373+7474+**Patterns:**
7575+- PPX syntax: `[%log info "message %s" arg]`
7676+- Structured logging with format strings
7777+- File-based logging to platform-specific directories
7878+7979+## Comments
8080+8181+**When to Comment:**
8282+- Module-level documentation: `(** ... *)` with markdown
8383+- Function documentation: Single-line `(** ... *)` before definitions
8484+- Inline explanations: `(* ... *)` for non-obvious logic
8585+- Algorithm explanations: Multi-line doc comments
8686+8787+**OCamldoc:**
8888+- Used for public APIs and complex functions
8989+- Format: `(** Description *)` before declarations
9090+- Markdown formatting supported in doc comments
9191+9292+**TODO Comments:**
9393+- Format: `(* TODO: description *)` or inline
9494+- Examples found in: `jj_tui/bin/global_funcs.ml`, `jj_tui/bin/graph_view.ml`
9595+9696+## Function Design
9797+9898+**Size:**
9999+- Generally under 50 lines per function
100100+- Large functions: Graph rendering algorithm (~100+ lines acceptable)
101101+- Extract helpers for complex logic
102102+103103+**Parameters:**
104104+- Named parameters: `~prefix:string ~rest:string`
105105+- Optional parameters: `?(working_copy = false)`
106106+- Labeled arguments preferred for clarity
107107+108108+**Return Values:**
109109+- Explicit `Result.t` for operations that can fail
110110+- Option types for nullable values
111111+- Direct values for infallible operations
112112+113113+## Module Design
114114+115115+**Exports:**
116116+- Library modules auto-exported from `lib/` directory
117117+- Explicit module signatures rarely used (prefer `.ml` only)
118118+- Functor pattern: `module Make (Vars : Global_vars.Vars) = struct ... end`
119119+120120+**Functors:**
121121+- Used extensively for dependency injection
122122+- Pattern: Most major modules parameterized over `Vars` signature
123123+- Examples: `Jj_ui.Make(Vars)`, `Graph_view.Make(Vars)`, `Jj_process.Make(Vars)`
124124+125125+**Patterns:**
126126+- Double semicolon termination: All top-level let bindings end with `;;`
127127+- PPX deriving: Heavy use of `[@@deriving yojson, yaml, show, eq]`
128128+- Custom operators: Lwd operators in `util.ml` (`<-$`, `$->`, `|>$`, etc.)
129129+130130+---
131131+132132+*Convention analysis: 2026-01-15*
133133+*Update when patterns change*
···11-# Changes to Match Original JJ Rendering Format
22-33-## Goal
44-Match the original `jj log` output format which displays commit information on two lines:
55-66-**Original jj format:**
77-```
88-@ ztooztwk eli.jambu@gmail.com 2026-01-15 14:05:59 235795c5
99-│ (empty) (no description set)
1010-```
1111-1212-## Changes Made
1313-1414-### 1. Updated `render_commit_content` in `graph_view.ml` (lines 19-79)
1515-1616-**Previous format (single line):**
1717-```
1818-change_id author_name timestamp (bookmarks) description
1919-```
2020-2121-**New format (two lines):**
2222-```
2323-Line 1: change_id email timestamp [bookmarks] commit_id_short
2424-Line 2: (empty) description
2525-```
2626-2727-**Key changes:**
2828-- Show **full email** instead of extracting name before `@`
2929-- Add **commit_id_short** (8 characters) at end of line 1
3030-- Move **description** to line 2
3131-- Add **(empty)** prefix when `node.empty` is true
3232-- Remove parentheses around bookmarks, show as space-separated list
3333-- Use `I.vcat` to create two-line image
3434-3535-### 2. Updated `render_graph_row` in `graph_view.ml` (lines 81-109)
3636-3737-**Problem:** When content is multi-line, the graph character only appears on the first line with `I.hcat [ graph_img; content_img ]`.
3838-3939-**Solution:** Detect multi-line content and manually create graph continuation for subsequent lines:
4040-4141-```ocaml
4242-if content_height > 1 then
4343- (* Replace node glyphs (○, @, ◌, ◆) with vertical bar │ *)
4444- let graph_continuation = replace_node_glyphs_with_bar row.graph_chars in
4545- (* Create each line with appropriate graph prefix *)
4646- let lines = List.init content_height (fun i ->
4747- let line_img = I.vcrop i 1 content_img in
4848- if i = 0 then I.hcat [ graph_img; line_img ]
4949- else I.hcat [ graph_continuation; line_img ]
5050- ) in
5151- I.vcat lines
5252-else
5353- I.hcat [ graph_img; content_img ]
5454-```
5555-5656-**How it works:**
5757-1. Check if content height > 1
5858-2. Create `graph_continuation` by replacing all node glyphs with `│`
5959-3. For each line:
6060- - Line 0: Use original `graph_chars` (contains node glyph)
6161- - Line 1+: Use `graph_continuation` (node glyph replaced with `│`)
6262-4. Vertically stack all lines
6363-6464-### 3. Color Scheme
6565-6666-**Line 1:**
6767-- `change_id`: cyan (bold cyan if working_copy, yellow if empty, lightmagenta if immutable)
6868-- `email`: dim white
6969-- `timestamp`: dim white
7070-- `bookmarks`: bold green
7171-- `commit_id_short`: dim cyan
7272-7373-**Line 2:**
7474-- `description`: white (dim if empty/preview, lightyellow if wip)
7575-7676-## Examples
7777-7878-### Simple commit (empty)
7979-```
8080-@ ztooztwk eli.jambu@gmail.com 2026-01-15 14:05:59 235795c5
8181-│ (empty) (no description set)
8282-```
8383-8484-### Commit with description
8585-```
8686-○ smqmznlq eli.jambu@gmail.com 2026-01-15 01:40:23 09a9f33f
8787-│ Add new feature
8888-```
8989-9090-### Commit with bookmarks
9191-```
9292-◆ noszsqtm eli.jambu@gmail.com 2025-11-22 00:26:06 main master 35b532af
9393-│ remove aarch64 linux because it doesn't seem to work
9494-```
9595-9696-### Complex graph
9797-```
9898-│ ○ nkwwwlnw eli.jambu@gmail.com 2026-01-15 00:30:16 89abd641
9999-│ │ rewrite
100100-```
101101-102102-## Testing
103103-104104-- ✅ `dune build` - compiles successfully
105105-- ✅ `dune runtest` - all existing tests pass
106106-- ✅ Multi-line rendering works correctly
107107-- ✅ Graph continuation characters display properly
108108-109109-## Files Modified
110110-111111-1. **`jj_tui/bin/graph_view.ml`**
112112- - `render_commit_content` (lines 19-79): Two-line format
113113- - `render_graph_row` (lines 81-109): Multi-line graph handling
114114-115115-## No Breaking Changes
116116-117117-- All existing functionality preserved
118118-- Tests pass without modification
119119-- Only visual formatting changed
+233
docs/jj_rebase.md
···11+See the sections below for details about the different ways of
22+specifying
33+which revisions to rebase where.
44+55+If a working-copy revision gets abandoned, it will be given a new,
66+empty
77+revision. This is true in general; it is not specific to this
88+command.
99+1010+### Specifying which revisions to rebase
1111+1212+With `--source/-s`, the command rebases the specified revision and
1313+its
1414+descendants to the destination. For example, `jj rebase -s M -o O`
1515+would
1616+transform your history like this (letters followed by an
1717+apostrophe are
1818+post-rebase versions):
1919+2020+```text
2121+O N'
2222+| |
2323+| N M'
2424+| | |
2525+| M O
2626+| | => |
2727+| | L | L
2828+| |/ | |
2929+| K | K
3030+|/ |/
3131+J J
3232+```
3333+3434+Each revision passed to `-s` will become a direct child of the
3535+destination,
3636+so if you instead run `jj rebase -s M -s N -o O` (or `jj rebase -s
3737+'M|N' -o
3838+O`) in the example above, then N' would instead be a direct child
3939+of O.
4040+4141+With `--branch/-b`, the command rebases the whole "branch"
4242+containing the
4343+specified revision. A "branch" is the set of revisions that
4444+includes:
4545+4646+* the specified revision and ancestors that are not also ancestors
4747+of the
4848+ destination
4949+* all descendants of those revisions
5050+5151+In other words, `jj rebase -b X -o Y` rebases revisions in the
5252+revset
5353+`(Y..X)::` (which is equivalent to `jj rebase -s 'roots(Y..X)' -o
5454+Y` for a
5555+single root). For example, either `jj rebase -b L -o O` or `jj
5656+rebase -b M
5757+-o O` would transform your history like this (because `L` and `M`
5858+are on the
5959+same "branch", relative to the destination):
6060+6161+```text
6262+O N'
6363+| |
6464+| N M'
6565+| | |
6666+| M | L'
6767+| | => |/
6868+| | L K'
6969+| |/ |
7070+| K O
7171+|/ |
7272+J J
7373+```
7474+7575+With `--revisions/-r`, the command rebases only the specified
7676+revisions to
7777+the destination. Any "hole" left behind will be filled by rebasing
7878+descendants onto the specified revisions' parent(s). For example,
7979+`jj rebase -r K -o M` would transform your history like this:
8080+8181+```text
8282+M K'
8383+| |
8484+| L M
8585+| | => |
8686+| K | L'
8787+|/ |/
8888+J J
8989+```
9090+9191+Multiple revisions can be specified, and any dependencies (graph
9292+edges)
9393+within the set will be preserved. For example, `jj rebase -r 'K|N'
9494+-o O`
9595+would transform your history like this:
9696+9797+```text
9898+O N'
9999+| |
100100+| N K'
101101+| | |
102102+| M O
103103+| | => |
104104+| | L | M'
105105+| |/ |/
106106+| K | L'
107107+|/ |/
108108+J J
109109+```
110110+111111+`jj rebase -s X` is similar to `jj rebase -r X::` and will behave
112112+the same
113113+if X is a single revision. However, if X is a set of multiple
114114+revisions,
115115+or if you passed multiple `-s` arguments, then `jj rebase -s` will
116116+make each
117117+of the specified revisions an immediate child of the destination,
118118+while
119119+`jj rebase -r` will preserve dependencies within the set.
120120+121121+Note that you can create a merge revision by repeating the `-o`
122122+argument.
123123+For example, if you realize that revision L actually depends on
124124+revision M
125125+in order to work (in addition to its current parent K), you can
126126+run `jj
127127+rebase -s L -o K -o M`:
128128+129129+```text
130130+M L'
131131+| |\
132132+| L M |
133133+| | => | |
134134+| K | K
135135+|/ |/
136136+J J
137137+```
138138+139139+### Specifying where to rebase the revisions
140140+141141+With `--onto/-o`, the command rebases the selected revisions onto
142142+the
143143+targets. Existing descendants of the targets will not be affected.
144144+See
145145+the section above for examples.
146146+147147+With `--insert-after/-A`, the selected revisions will be inserted
148148+after the
149149+targets. This is similar to `-o`, but if the targets have any
150150+existing
151151+descendants, then those will be rebased onto the rebased selected
152152+revisions.
153153+154154+For example, `jj rebase -r K -A L` will rewrite history like this:
155155+```text
156156+N N'
157157+| |
158158+| M | M'
159159+|/ |/
160160+L => K'
161161+| |
162162+| K L
163163+|/ |
164164+J J
165165+```
166166+167167+The `-A` (and `-B`) argument can also be used for reordering
168168+revisions. For
169169+example, `jj rebase -r M -A J` will rewrite history like this:
170170+```text
171171+M L'
172172+| |
173173+L K'
174174+| => |
175175+K M'
176176+| |
177177+J J
178178+```
179179+180180+With `--insert-before/-B`, the selected revisions will be inserted
181181+before
182182+the targets. This is achieved by rebasing the selected revisions
183183+onto the
184184+target revisions' parents, and then rebasing the target revisions
185185+and their
186186+descendants onto the rebased revisions.
187187+188188+For example, `jj rebase -r K -B L` will rewrite history like this:
189189+```text
190190+N N'
191191+| |
192192+| M | M'
193193+|/ |/
194194+L => L'
195195+| |
196196+| K K'
197197+|/ |
198198+J J
199199+```
200200+201201+The `-A` and `-B` arguments can also be combined, which can be
202202+useful around
203203+merges. For example, you can use `jj rebase -r K -A J -B M` to
204204+create a new
205205+merge (but `jj rebase -r M -o L -o K` might be simpler in this
206206+particular
207207+case):
208208+```text
209209+M M'
210210+| |\
211211+L L |
212212+| => | |
213213+| K | K'
214214+|/ |/
215215+J J
216216+```
217217+218218+To insert a commit inside an existing merge with `jj rebase -r O
219219+-A K -B M`:
220220+```text
221221+O N'
222222+| |\
223223+N | M'
224224+|\ | |\
225225+| M | O'|
226226+| | => |/ /
227227+| L | L
228228+| | | |
229229+K | K |
230230+|/ |/
231231+J J
232232+```
233233+