Here's a comprehensive implementation plan for AI Rebase, drawing from issue #177 , the existing split architecture in issue #196 , and the codebase structure .
The AI Rebase is the inverse of the split feature — instead of one commit → many, it's many commits → fewer logical ones. You can mirror the existing split pipeline but reverse the data flow. The key files to model after are omni_commit.rs on the Rust side and the commit view components in src/views/commit/ .
Add a new Tauri command in src-tauri/src/ (e.g., omni_rebase.rs) that:
- Collects commit metadata for the selected range — for each commit, gather: SHA, message, author, timestamp, and the list of files changed with their diffs
- Builds per-commit dossiers — a stripped-down summary per commit, similar to what you described in (https://github.com/edgeleap/omni-app/issues/196#issuecomment-3796993207): file paths touched, diff stats (additions/deletions), and a truncated diff snippet
- Deduplicates file changes — track how many times each file appears across the selected commits (this feeds the "file change reduction" metric)
// src-tauri/src/omni_rebase.rs (new file)
#[tauri::command]
pub async fn ai_rebase_analyze(
repo_path: String,
commit_shas: Vec<String>, // selected commits
) -> Result<RebaseAnalysis, String> {
// 1. git log --format for each SHA → collect metadata
// 2. git diff SHA~1..SHA for each → build dossiers
// 3. Return RebaseAnalysis { dossiers, file_touch_counts }
}
#[tauri::command]
pub async fn ai_rebase_execute(
repo_path: String,
rebase_plan: RebasePlan, // the AI-decided groupings
) -> Result<Vec<NewCommit>, String> {
// interactive rebase execution via git
}Register these in main.rs alongside the existing commit commands .
This is the core AI logic. Following the recursive approach you described in (https://github.com/edgeleap/omni-app/issues/196#issuecomment-3796993207) , build this as a TypeScript service (since AI calls likely go through the frontend):
// src/services/rebaseGrouper.ts (new file)
interface CommitDossier {
sha: string;
message: string;
files: string[]; // paths touched
diffStats: { additions: number; deletions: number };
diffSnippet: string; // truncated for token budget
}
interface RebaseGroup {
commits: CommitDossier[];
proposedMessage: string;
category: string; // e.g., "auth", "database", "UI"
}
// Step 1: Heuristic pre-grouping (fast, no AI needed)
function preGroupByFileOverlap(dossiers: CommitDossier[]): CommitDossier[][] {
// Group commits that touch the same files together
// Uses set intersection: if commits A and B share >50% files, group them
// This is the "recursive" part — split into buckets, then sub-bucket
}
// Step 2: AI refinement (send pre-groups to LLM)
async function aiRefineGroups(
preGroups: CommitDossier[][],
userPrompt?: string // #196 mentions user wishes
): Promise<RebaseGroup[]> {
// Send each pre-group to LLM with prompt:
// "Given these commits, should they stay as one group or be split further?"
// Works on AFM because each call is small (one group at a time)
}
// Step 3: AI message generation (reuse commit enricher)
async function enrichGroupMessages(
groups: RebaseGroup[]
): Promise<RebaseGroup[]> {
// Reuse existing commit enricher algorithm
// Carry over relevant original descriptions
}The recursive design means it scales from 10 to 1000 commits — more commits just means more iterations, not bigger payloads per AI call . @dernDren161's existing DiffSense algorithm can be reused for the diff analysis step within each dossier .
The actual rebase needs to happen in Rust via git2 or shell commands:
// Inside omni_rebase.rs
pub fn execute_rebase_plan(
repo_path: &str,
groups: Vec<RebaseGroup>
) -> Result<(), String> {
// Option A: git rebase -i with auto-generated todo list
// - Mark commits as "squash" or "fixup" per group
// - Set the new commit message per group
// Option B: Soft reset + selective re-commit (simpler)
// 1. git branch backup-<timestamp> (safety)
// 2. git reset --soft <base_commit>
// 3. For each group, stage only the group's files and commit
// 4. This naturally deduplicates file touches
}Option B (soft reset + re-commit) is probably simpler and more reliable than generating an interactive rebase script, especially since you're rewriting history entirely anyway .
Build on the existing commit view components :
| Component | Location | Purpose |
|---|---|---|
RebaseToggle |
Extend BottomBar.tsx |
Toggle to switch commit list into "select for rebase" mode |
RebaseSelectionList |
New component in src/views/commit/components/ |
Checkboxes on each commit row |
RebasePreview |
New component | Shows proposed groupings before executing |
RebaseContextMenu |
Extend existing context menu | Right-click → "Auto Rebase" option |
The state lives in a new store:
// src/stores/commit/rebaseStore.ts (new file)
interface RebaseStore {
isRebaseMode: boolean;
selectedCommitShas: string[];
proposedGroups: RebaseGroup[] | null;
isAnalyzing: boolean;
isExecuting: boolean;
// Actions
toggleRebaseMode: () => void;
toggleCommitSelection: (sha: string) => void;
analyzeSelected: () => Promise<void>; // triggers Phase 2
executeRebase: () => Promise<void>; // triggers Phase 3
reset: () => void;
}User selects commits in UI
|
v
[Rust] ai_rebase_analyze() → commit dossiers
|
v
[TS] preGroupByFileOverlap() → heuristic clusters
|
v
[TS] aiRefineGroups() → LLM validates/adjusts groups
|
v
[TS] enrichGroupMessages() → clean commit messages
|
v
Preview shown to user (editable)
|
v
[Rust] ai_rebase_execute() → git operations
|
v
Clean commit history
- Safety first: Always create a backup branch before rebase. Show it in the UI so users can undo .
- AFM-compatible: Keep per-AI-call token budgets small by using the recursive approach — group-by-group, not all commits at once. This is the key insight from (https://github.com/edgeleap/omni-app/issues/196#issuecomment-3796993207) .
- Reuse the commit enricher you already have for description generation — no need to build new prompt engineering for that .
- The heuristic pre-grouping step (file overlap detection) does the heavy lifting for free. AI only needs to validate and refine, which makes it fast even on AFM .
- User prompt support from (https://github.com/edgeleap/omni-app/issues/196#issuecomment-3797070923) — the existing
PromptOverlay.tsxcomponent can be reused to let users guide the grouping ("keep .md files separate", etc.) .
src-tauri/src/omni_rebase.rs # Rust: git operations + dossier builder
src/services/rebaseGrouper.ts # TS: recursive grouping algorithm
src/stores/commit/rebaseStore.ts # TS: UI state management
src/views/commit/components/RebasePreview.tsx # Preview grouped commits
src/views/commit/hooks/useRebase.ts # Hook wiring store → Tauri commands
The biggest win is that your split infra (omni_commit.rs, the DiffSense algorithm, the PromptOverlay, the GenerateButton) gives you ~60% of what you need already — you're essentially running the same pipeline in reverse .