Overview
Retcon transforms messy git branch history into a clean, reviewable story. It takes a history specification describing the logical commits you want and reconstructs them from your working branch.
The Problem
Development is messy. A feature branch accumulates:
- "WIP" commits
- "Fix compilation" commits
- "Actually fix it this time" commits
- Interleaved work on multiple concerns
- Debug code that got committed and later removed
But reviewers deserve a clean story. Each commit should be a conceptual layer that builds toward the final picture, understandable on its own.
The Solution
Retcon separates two concerns:
- What commits should exist (the history spec) - a human decision, possibly LLM-assisted
- How to create those commits (the reconstruction) - a deterministic loop with LLM-powered extraction
You describe the logical commits you want. Retcon reconstructs them from your changes, handling the tedious work of extracting the right pieces, making them compile, and crafting coherent commit messages.
Architecture
Retcon is built on determinishtic, which blends deterministic Rust code with LLM-powered reasoning:
- Deterministic (Rust): Branch management, diff computation, build/test execution, the loop structure
- Non-deterministic (LLM): Extracting relevant changes for each commit, diagnosing and fixing build failures, writing commit messages
This follows the patchwork philosophy: do things deterministically that are deterministic.
Workflow
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Source Branch │────▶│ History Spec │────▶│ Cleaned Branch │
│ (messy) │ │ (TOML) │ │ (reviewable) │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│ │ ▲
│ │ │
▼ ▼ │
analyze & retcon reconstructed
plan commits reconstruction commits
(LLM-assisted) loop
- Analyze your source branch and design the logical commit sequence
- Write a history specification describing each commit
- Run retcon to reconstruct the clean history
- Review the result and iterate if needed
User's Guide
This guide walks you through using retcon to clean up a messy git branch.
Prerequisites
- A git repository with a messy feature branch
- The branch has been pushed or you have a backup
retconinstalled and in your PATH- An LLM agent available (retcon uses Claude Code by default)
Quick Start
# 1. Generate guidance for creating a spec
retcon prompt > guidance.md
# 2. Give the guidance to your agent to create a spec
# e.g. in `my-spec.toml`
# 3. Run the reconstruction
retcon execute my-spec.toml
Step 1: Create the Spec with Your Agent
The retcon prompt command outputs guidance you can give to your LLM agent. The agent will analyze your diffs and propose a series of commits.
# Get the guidance prompt
retcon prompt
Give this prompt to your agent along with context about your branch:
# Show the agent your changes
git diff origin/main...my-feature-branch
The agent will:
- Analyze the diff to understand what changed
- Identify logical groupings (refactors, features, tests, etc.)
- Propose a commit sequence with messages and hints
Iterate with your agent until you're happy with the structure. Ask questions like:
- "Can we split commit 2 into two parts?"
- "Should the config changes be in their own commit?"
- "Reorder so refactors come before features"
Once you've agreed on the structure, have the agent write out the TOML file:
Write this plan as a retcon spec file to my-spec.toml
Manual Spec Creation
You can also create the spec manually. First understand what changed:
# See the full diff against target
git diff origin/main...my-feature-branch
# See which files changed
git diff origin/main...my-feature-branch --stat
# See the messy commit history (for context)
git log origin/main..my-feature-branch --oneline
Focus on the diff, not the commits. The diff shows what actually changed; the commits show how you got there (which is what we're cleaning up).
Then create a TOML file describing the clean history you want:
# my-spec.toml
source = "my-feature-branch" # Your messy branch
remote = "origin/main" # Target for the PR
cleaned = "my-feature-branch-clean" # New clean branch
[[commit]]
message = "refactor: extract validation into dedicated module"
hints = """
Move validate_user() and validate_session() from lib.rs to validation.rs.
Include the ValidationError enum.
Pure reorganization - no behavior changes.
"""
[[commit]]
message = "feat: add OAuth provider support"
hints = """
New oauth.rs module with OAuthProvider trait.
Includes Google and GitHub implementations.
Token refresh logic in token.rs.
"""
[[commit]]
message = "test: add OAuth integration tests"
hints = """
New file tests/oauth_test.rs.
Mock provider for testing.
"""
Tips for Good Specs
- Refactors first: Put code reorganization before new features
- One concept per commit: Each commit should do one thing
- Specific hints: Name files and functions, not just concepts
- Note exclusions: If a file has changes for multiple commits, say which parts belong where
Step 2: Run Retcon
retcon execute my-spec.toml
Retcon will:
- Create the
cleanedbranch from the merge-base - For each commit in order:
- Show the LLM the diff and your hints
- Apply the relevant changes
- Run
cargo check(build verification) - If it passes, mark complete and move on
- If it fails, try to fix it
- If stuck, stop and ask for help
Watching Progress
Retcon prints progress as it works:
Resuming from commit 1/3: refactor: extract validation
Created commit
Building...
Build passed
✓ Commit complete
Commit 2/3: feat: add OAuth provider support
Created commit
Building...
Build failed, consulting LLM...
Created WIP commit
Building...
Build passed
✓ Commit complete
The Spec File is State
Retcon updates your spec file as it works. After running, you'll see:
[[commit]]
message = "refactor: extract validation into dedicated module"
hints = "..."
history = [
{ commit_created = "a1b2c3d" },
"complete",
]
[[commit]]
message = "feat: add OAuth provider support"
hints = "..."
history = [
{ commit_created = "e4f5g6h" },
{ commit_created = "i7j8k9l" }, # WIP fix
"complete",
]
Step 3: Handle Stuck States
Sometimes retcon can't proceed:
Commit 2/3: feat: add OAuth provider support
...
Build failed, consulting LLM...
LLM: "I'm stuck. OAuthProvider depends on SessionManager which
isn't in the diff yet - it's probably in commit 3."
✗ Stuck - stopping
Your spec now shows:
history = [
{ commit_created = "a1b2c3d" },
{ stuck = "OAuthProvider depends on SessionManager..." },
]
To Continue
- Understand the problem: Read the stuck message
- Fix it: Edit hints, reorder commits, or manually adjust code
- Add a resolved entry: Tell retcon what you changed
history = [
{ commit_created = "a1b2c3d" },
{ stuck = "OAuthProvider depends on SessionManager..." },
{ resolved = "Reordered commits 2 and 3 - SessionManager needs to come first" },
]
- Resume:
retcon execute my-spec.toml
Retcon will retry with your resolution note as context.
If You Don't Add Resolved
$ retcon execute my-spec.toml
Resuming from commit 2/3: feat: add OAuth provider support
✗ Previously stuck - add a `resolved` entry to continue
Edit the spec file and add after the `stuck` entry:
{ resolved = "description of what you changed" }
This ensures the LLM knows what changed before retrying.
Step 4: Review the Result
When complete:
# Check out the clean branch
git checkout my-feature-branch-clean
# Review the history
git log --oneline
# Compare to original (should be identical content)
git diff my-feature-branch
# (should show nothing)
Handling WIP Commits
If retcon created WIP commits during fixes, you can squash them:
git checkout my-feature-branch-clean
git rebase -i origin/main
# Mark WIP commits as "fixup" to fold them into their parent
Or keep them for transparency about the reconstruction process.
Common Patterns
Circular Dependencies
Problem: Commit A needs something from commit B, but B depends on A.
Solution: Combine them into one commit, or extract the shared piece into a third commit that comes first.
# Before (broken)
[[commit]]
message = "feat: add TokenStore"
# ...
[[commit]]
message = "feat: add SessionManager"
# SessionManager uses TokenStore, but TokenStore uses SessionManager!
# After (fixed)
[[commit]]
message = "feat: add TokenStore and SessionManager"
hints = "These have circular dependencies - must be in same commit"
Interleaved Changes
Problem: One file has changes for multiple logical commits.
Solution: Use hints to specify which changes belong where.
[[commit]]
message = "refactor: rename foo to bar"
hints = """
In src/lib.rs: ONLY the foo→bar renames (lines 10-50 of the diff).
Do NOT include the new baz() function - that's commit 2.
"""
[[commit]]
message = "feat: add baz functionality"
hints = """
In src/lib.rs: the new baz() function.
Builds on the bar rename from commit 1.
"""
Missing Dependencies
Problem: Build fails because something from a later commit is needed.
Solution: Either reorder commits, or pull the dependency into the current commit's hints.
[[commit]]
message = "feat: add OAuth flow"
hints = """
Include the OAuthConfig struct even though it's "supposed" to be
in the config commit - we need it here for the code to compile.
"""
Troubleshooting
"Failed to find merge-base"
Your source and remote branches don't share history. Make sure:
sourceis your feature branch nameremoteis the target branch (e.g.,origin/main)- Both branches exist
"No more changes to extract"
The diff between cleaned and source is empty. This means either:
- All changes have been extracted (success!)
- The branches are identical (nothing to do)
- Wrong branch names in the spec
Build Keeps Failing
If the LLM keeps getting stuck:
- Check if changes are correctly split - maybe they need to be combined
- Add more specific hints about what to include
- Manually make the fix and add a
resolvedentry
Want to Start Over
# Delete the clean branch
git branch -D my-feature-branch-clean
# Remove history from spec (or delete and recreate)
# Edit my-spec.toml, remove all `history = [...]` fields
# Run again
retcon execute my-spec.toml
History Specification
The history specification is a TOML file that describes:
- Which branches to work with
- The logical commits to create
- Hints to guide the LLM in extracting each commit
- Execution history tracking progress and state
Format
# Branches
source = "feature-oauth" # Branch containing your changes
remote = "origin/main" # Target branch for the PR
cleaned = "feature-oauth-clean" # Branch to create with clean history
# Commits (in order)
[[commit]]
message = "refactor: extract user validation into dedicated module"
hints = """
Move validate_user, validate_session, and related helpers from lib.rs to validation.rs.
Pure reorganization - no behavior changes.
Tests will need import updates.
"""
history = [
{ commit_created = "a1b2c3d" },
"complete",
]
[[commit]]
message = "feat: add OAuth 2.0 provider authentication"
hints = """
New oauth.rs module with OAuthProvider trait and implementations.
Token refresh logic is subtle - ensure the refresh_token flow is complete.
Builds on validation module from previous commit.
"""
history = [
{ commit_created = "e4f5g6h" },
{ commit_created = "f7g8h9i" }, # WIP fix
"complete",
]
[[commit]]
message = "feat: add backward compatibility shim for legacy auth"
hints = """
LegacyAuthAdapter in compat.rs wraps old auth calls.
Should be thin - mostly delegates to new OAuth internals.
"""
# history absent - not yet started
Fields
Branch Configuration
| Field | Required | Description |
|---|---|---|
source | Yes | The branch containing all your changes (the messy history) |
remote | Yes | The upstream branch this will merge into (e.g., origin/main) |
cleaned | Yes | The new branch to create with reconstructed history |
The cleaned branch starts from git merge-base source remote - the point where your work diverged from the target.
Commit Entries
Each [[commit]] represents one logical commit in the final history, applied in order.
| Field | Required | Description |
|---|---|---|
message | Yes | The main commit message (first line) |
hints | No | Guidance for the LLM on what changes belong in this commit |
history | No | Execution log tracking commits created and status (managed by retcon) |
History Entries
The history field is a vector that retcon appends to as it works. Each entry is one of:
#![allow(unused)] fn main() { enum HistoryEntry { CommitCreated(String), // A commit was created (main or WIP fix) Stuck(String), // LLM assessed it cannot proceed Resolved(String), // Human resolved the stuck state Complete, // This logical commit is done } }
In TOML:
history = [
{ commit_created = "a1b2c3d" },
{ commit_created = "b4c5d6e" }, # WIP fix
{ stuck = "Missing type definition - may need to reorder commits" },
{ resolved = "Reordered commits 2 and 3 to resolve dependency" },
]
The history tells you the commit's status:
| History state | Meaning |
|---|---|
| Absent or empty | Not yet started |
Ends with commit_created | In progress, build may not pass yet |
Ends with stuck | Paused, needs human intervention |
Ends with resolved | Human addressed the issue, ready to retry |
Ends with complete | Done, proceed to next commit |
When resuming, retcon finds the first commit whose history doesn't end in complete and continues from there.
Resolving Stuck States
When retcon gets stuck, it stops and asks for human intervention. To continue:
- Read the
stuckmessage to understand the problem - Make changes (edit hints, reorder commits, manually fix code, etc.)
- Add a
resolvedentry describing what you changed:{ resolved = "Combined commits 2 and 3 - they had circular dependencies" } - Run retcon again - it will retry with your resolution note as context
Writing Good Hints
Hints help the LLM extract the right changes. Good hints:
- Name specific files or functions that should be modified
- Describe the nature of changes (refactor, new feature, fix, etc.)
- Note dependencies on previous commits
- Flag tricky areas where care is needed
- Mention what to exclude if changes from multiple concerns touch the same files
Bad hints are vague ("make it work") or redundant with the message.
Example: OAuth Feature
source = "feature-oauth"
remote = "origin/main"
cleaned = "feature-oauth-clean"
[[commit]]
message = "refactor: extract validation logic to prepare for OAuth"
hints = """
Create src/validation.rs with:
- validate_credentials() moved from auth.rs
- validate_session() moved from session.rs
- ValidationError enum
Update imports in auth.rs, session.rs, and tests.
No behavior changes - just reorganization.
"""
[[commit]]
message = "feat: add OAuth configuration and dependencies"
hints = """
- Add oauth2 crate to Cargo.toml
- Create src/oauth/mod.rs with OAuthConfig struct
- Add oauth section to config.toml parsing
Does NOT include the actual OAuth flow yet - just setup.
"""
[[commit]]
message = "feat: implement OAuth provider authentication flow"
hints = """
Main implementation in src/oauth/:
- provider.rs: OAuthProvider trait
- google.rs, github.rs: provider implementations
- token.rs: token refresh logic (careful with the refresh window)
Wire into existing auth system via AuthMethod enum variant.
"""
[[commit]]
message = "feat: add backward compatibility for password auth"
hints = """
LegacyPasswordAuth adapter in src/compat.rs.
Thin wrapper - delegates to new validation module.
Add deprecation warnings when legacy path is used.
"""
[[commit]]
message = "test: add OAuth integration tests"
hints = """
New test file tests/oauth_integration.rs.
Mock provider for testing without real OAuth endpoints.
Test token refresh, expiry handling, error cases.
"""
Creating a History Spec
This guide helps you (or an LLM assistant) create a history specification from a messy branch.
Step 1: Understand the Changes
First, examine what actually changed:
# See the full diff against the target branch
git diff origin/main...feature-branch
# See the commit history (for context, not structure)
git log origin/main..feature-branch --oneline
# See which files changed
git diff origin/main...feature-branch --stat
The commit history shows how the work happened, but the diff shows what actually changed. Focus on the diff - that's what needs to be reconstructed.
Step 2: Identify the Strands
Look for distinct "strands" of work in the diff:
- Refactorings: Code movement, renames, reorganization (no behavior change)
- New features: New functionality being added
- Bug fixes: Corrections to existing behavior
- Cleanups: Style changes, removing dead code, updating dependencies
- Tests: New or modified tests
Note which files belong to which strand. Watch for files that have changes from multiple strands - these need careful handling in the hints.
Step 3: Design the Commit Sequence
Order commits to tell a clear story:
Principles
-
Refactorings before features: Extract, rename, reorganize first. Then build on the clean foundation.
-
One concept per commit: Each commit should have a single purpose that can be stated clearly.
-
Buildable is nice, not required: Ideally each commit compiles and tests pass. But conceptual clarity trumps buildability - retcon will help fix compilation issues.
-
Dependencies flow forward: If commit B depends on commit A, A comes first.
Common Patterns
The Extract-Then-Use Pattern
1. Extract X into its own module (refactor)
2. Add new capability to X (feature)
3. Use new capability in Y (feature)
The Foundation-Then-Feature Pattern
1. Add dependencies and configuration (setup)
2. Implement core functionality (feature)
3. Wire into existing system (integration)
4. Add tests (verification)
The Parallel Concerns Pattern When changes are independent, order doesn't matter much:
1. Fix bug in auth (fix)
2. Update logging format (cleanup)
3. Add new API endpoint (feature)
Step 4: Write the Spec
For each commit, write:
The Message
Follow conventional commit style:
refactor:- code changes that don't affect behaviorfeat:- new functionalityfix:- bug fixestest:- adding or modifying testsdocs:- documentation changeschore:- maintenance tasks
The message should be clear enough that someone reading git log --oneline understands the progression.
The Hints
Hints guide the LLM in extracting the right changes. Include:
What to include:
hints = """
Files: src/auth.rs, src/validation.rs
Functions: validate_user(), validate_session()
The ValidationError enum and its From implementations.
"""
What to exclude:
hints = """
Extract ONLY the validation logic.
Do NOT include the OAuth changes to auth.rs (that's commit 3).
Do NOT include the new test file yet (that's commit 5).
"""
Dependencies:
hints = """
Builds on the validation module from commit 1.
Uses the OAuthConfig added in commit 2.
"""
Tricky areas:
hints = """
The token refresh has a race condition window - make sure
both the check and the refresh are included together.
"""
Step 5: Validate the Spec
Before running retcon, sanity check:
- Coverage: Do the commits cover all the changes in the diff?
- Order: Do dependencies flow forward?
- Clarity: Could someone understand the PR from reading just the commit messages?
- Hints: Are the tricky parts called out?
Example Analysis
Given this messy history:
a]1b2c3 WIP oauth stuff
d4e5f6 fix compile errors
g7h8i9 more oauth work
j0k1l2 extract validation (should have done this first)
m3n4o5 fix tests
p6q7r8 actually fix oauth token refresh
s9t0u1 remove debug logging
A good reconstruction might be:
[[commit]]
message = "refactor: extract validation logic to dedicated module"
hints = "The j0k1l2 changes, but applied first..."
[[commit]]
message = "feat: add OAuth provider authentication"
hints = "Core oauth from a1b2c3, g7h8i9, p6q7r8, minus debug logging..."
[[commit]]
message = "test: update tests for OAuth support"
hints = "Test fixes from m3n4o5..."
The messy "how it happened" becomes a clean "conceptual layers" story.
The Reconstruction Loop
Retcon reconstructs clean history through a deterministic loop with LLM-powered steps.
Algorithm
1. Load history spec from TOML
2. Create cleaned branch from merge-base(source, remote) if needed
3. Find first commit where history doesn't end in "complete"
4. For each remaining commit:
a. Compute diff: cleaned..source
b. LLM: Extract relevant changes for this commit from diff
c. LLM: Apply changes and create commit
d. Append CommitCreated { hash } to history, save TOML
e. Loop:
- Run build and tests
- If pass: append Complete to history, save TOML, next commit
- If fail:
- Compute diff: cleaned..source
- LLM: Assess - can you make progress?
- If yes: fix, create WIP commit, append CommitCreated, save TOML
- If no: append Stuck { summary }, save TOML, stop
5. Report results
Deterministic vs LLM Boundaries
Following the patchwork philosophy ("do things deterministically that are deterministic"):
| Deterministic (Rust) | LLM-powered |
|---|---|
| Parse TOML spec | Extract relevant diff hunks |
| Create/checkout branches | Decide what changes belong together |
| Compute diffs | Apply changes to files |
| Run build/test commands | Write commit messages |
| Track loop state | Diagnose build failures |
| Determine what else to pull from source |
The Fix Loop
When a commit doesn't build or tests fail, retcon enters a fix loop:
┌─────────────────────────────────────────────────────────┐
│ Fix Loop │
│ │
│ ┌──────────┐ ┌───────────┐ ┌──────────────────┐ │
│ │ Run │───▶│ Pass? │─Y─▶│ Append Complete │ │
│ │ build │ └───────────┘ │ Next commit │ │
│ └──────────┘ │N └──────────────────┘ │
│ ▲ ▼ │
│ │ ┌───────────┐ │
│ │ │ Compute │ │
│ │ │ new diff │ │
│ │ └───────────┘ │
│ │ │ │
│ │ ▼ │
│ │ ┌─────────────────┐ │
│ │ │ LLM: Can you │ │
│ │ │ make progress? │ │
│ │ └─────────────────┘ │
│ │ │Y │N │
│ │ ▼ ▼ │
│ │ ┌──────────┐ ┌──────────────┐ │
│ │ │ Fix + │ │ Append Stuck │ │
│ │ │ WIP │ │ Stop │ │
│ │ │ commit │ └──────────────┘ │
│ │ └──────────┘ │
│ │ │ │
│ │ ▼ │
│ │ ┌──────────────────┐ │
│ │ │ Append │ │
│ │ │ CommitCreated │ │
│ │ │ Save TOML │ │
│ │ └──────────────────┘ │
│ │ │ │
│ └───────────┘ │
└─────────────────────────────────────────────────────────┘
Key insight: each iteration recomputes the diff from cleaned to source. This means the LLM can pull in additional changes that it now realizes are needed - perhaps a helper function, a type definition, or an import that the original extraction missed.
LLM Progress Assessment
Instead of a fixed iteration limit, the LLM assesses after each failed build:
"Given the build errors and the remaining diff from source, can you make progress? Or are you stuck?"
The LLM returns one of:
- Progress: "I can fix this" → creates WIP commit, loop continues
- Stuck: "I need help:
" → appends Stuck, stops
This lets the LLM recognize situations it can't resolve:
- Circular dependencies between commits
- Missing context it can't infer
- Ambiguous hints that need clarification
- Changes that don't belong together
WIP Commits
Fix iterations create commits prefixed with WIP::
feat: add OAuth provider authentication
WIP: add missing TokenRefresh import
WIP: include refresh_token helper that was needed
This creates an honest record of what happened. The history tracks every commit:
history = [
{ commit_created = "a1b2c3d" }, # initial attempt
{ commit_created = "e4f5g6h" }, # WIP: add missing import
{ commit_created = "i7j8k9l" }, # WIP: include helper
"complete",
]
Options for handling WIP commits:
- Keep them: Transparent history of the reconstruction
- Squash manually:
git rebase -ito fold WIPs into their parent - Future:
--squash-wipflag to auto-collapse
Resuming After Stuck
When retcon encounters a Stuck entry, it requires explicit human resolution before continuing:
- Stuck: retcon stops and shows the summary
- Intervene: Edit hints, reorder commits, make manual fixes
- Resolve: Add a
resolvedentry to the history describing what you changed:{ resolved = "Reordered commits to resolve circular dependency" } - Resume: Run retcon again - it passes your resolution note to the LLM as context
If you try to resume without adding a resolved entry, retcon will stop immediately and remind you to add one. This ensures the LLM gets context about what changed.
The TOML file is the complete state - you can edit it, inspect the history, and resume at any point.
Tools Provided to LLM
During reconstruction, the LLM has access to:
| Tool | Purpose |
|---|---|
read_file | Read file contents from working tree |
write_file | Write file contents |
read_diff | Get the current cleaned..source diff |
run_build | Execute build command, get output |
run_tests | Execute test command, get output |
create_commit | Stage all changes and commit with message |
The LLM does NOT have:
- Direct git access (retcon manages branches)
- Network access
- Ability to modify the source branch
Example Session
$ retcon reconstruct history-spec.toml
Loading spec: history-spec.toml
Source: feature-oauth
Remote: origin/main
Cleaned: feature-oauth-clean
Creating cleaned branch from merge-base...
Base commit: a1b2c3d
Commit 1/4: refactor: extract validation logic
Computing diff (847 lines)...
Extracting relevant changes...
Creating commit...
Building... PASS
Tests... PASS
✓ Commit created
Commit 2/4: feat: add OAuth configuration
Computing diff (623 lines)...
Extracting relevant changes...
Creating commit...
Building... FAIL (missing import)
Fix attempt 1:
Consulting diff for missing pieces...
Adding TokenConfig import...
Creating WIP commit...
Building... PASS
Tests... PASS
✓ Commit created (1 WIP)
Commit 3/4: feat: implement OAuth flow
Computing diff (412 lines)...
...
Complete!
4 logical commits created
2 WIP fix commits
Branch: feature-oauth-clean
To squash WIP commits:
git checkout feature-oauth-clean
git rebase -i HEAD~6
Example: Stuck and Resume
$ retcon execute history-spec.toml
...
Commit 3/4: feat: implement OAuth flow
Computing diff (412 lines)...
Extracting relevant changes...
Creating commit...
Building... FAIL (undefined type TokenStore)
Assessing progress...
Fix attempt 1:
Adding TokenStore from diff...
Creating WIP commit...
Building... FAIL (TokenStore needs SessionManager)
Assessing progress...
LLM: "I'm stuck. TokenStore depends on SessionManager which depends on
TokenStore - circular dependency. The commits may need reordering,
or these changes need to be in the same commit."
✗ Stuck - stopping
$ # Try to resume without resolving...
$ retcon execute history-spec.toml
Resuming from commit 3/4: feat: implement OAuth flow
✗ Previously stuck - add a `resolved` entry to continue
Edit the spec file and add after the `stuck` entry:
{ resolved = "description of what you changed" }
$ # User edits spec - combines commits 3 and 4
$ vim history-spec.toml
# Add: { resolved = "Combined OAuth flow and SessionManager into one commit" }
$ retcon execute history-spec.toml
Resuming from commit 3/4: feat: implement OAuth flow
Resolved: Combined OAuth flow and SessionManager into one commit
Computing diff...
...
Git History Cleanup for PR Preparation
Overview
This script helps transform a messy git branch history into a clear, reviewable story suitable for pull requests. The goal is to create commits that act as conceptual layers, where each commit is understandable on its own and builds toward the final picture.
Parameters
- pr_description (required): A brief description of what this PR accomplishes overall. This provides context for how individual commits should fit into the larger narrative.
- target_branch (required): The branch this PR will be merged into (e.g.,
origin/main,origin/develop). This determines the base for commit analysis and cleanup.
Constraints for parameter acquisition:
- You MUST ask for all required parameters upfront in a single prompt rather than one at a time
- You MUST support multiple input methods including:
- Direct input: Text provided directly in the conversation
- File path: Path to a local file containing the PR description
- URL: Link to an internal resource
- Other methods: You SHOULD be open to other ways the user might want to provide the data
- You MUST use appropriate tools to access content based on the input method
- You MUST confirm successful acquisition of all parameters before proceeding
- You SHOULD save the PR description to a consistent location for reference during the cleanup process
Steps
1. Establish and Confirm Cleanup Principles
Present the suggested principles for guiding the cleanup process and verify they align with the user's goals.
Suggested Commit Structure Principles:
- Each commit should be a conceptual layer that builds toward the final picture
- Separate refactorings (no behavior change) from behavior-defining changes
- Minimize commits that modify the same code repeatedly (different parts of the same file is fine)
- Prioritize: conceptual clarity (layers) > independent buildability > test passage
Suggested Commit Message Principles:
- Explain briefly what the commit does
- More importantly, explain how it fits into the overall PR narrative
- Indicate if this lays groundwork for future changes
- Note dependencies on future work when relevant
Constraints:
- You MUST present these principles as suggestions, not requirements
- You MUST ask the user if they agree with these principles or have different priorities
- You MUST allow the user to modify, add, or remove principles based on their context
- You MUST confirm the final set of principles before proceeding with any git operations
- You SHOULD provide examples of how different principles would affect commit organization
- You MUST NOT proceed until the user explicitly agrees to the cleanup approach
2. Create Clean Branch and Extract Changes
Create a clean working branch and extract all changes as a diff file for safe incremental application.
Constraints:
- You MUST verify the working directory is clean (no unstaged or staged changes) before proceeding
- You MUST create a backup branch named
backup-[original-branch-name]-[timestamp] - You MUST verify the backup was created successfully before proceeding
- You MUST create a clean working branch named
[original-branch-name]-[date]-cleanbased on the target branch - You MUST generate a complete diff file:
git diff [clean-branch] [original-branch] > /tmp/HISTORY_FULL_CHANGES.diff - You MUST verify the diff file contains all expected changes
- You MUST switch to the clean branch for all subsequent work
- You MUST inform the user of both branch names and explain the diff-based approach
3. Analyze Changes and Development Story
Examine the full-changes.diff and any helpful context from original commits to understand the development story and identify cleanup opportunities.
Constraints:
- You MUST analyze the
/tmp/HISTORY_FULL_CHANGES.difffile to understand what actually changed - You SHOULD examine original commit history for context about intent and development strands
- You MUST identify the main "strands" of development by analyzing the diff:
- What are the major pieces and how do they interact?
- Which changes are refactorings vs behavior changes vs orthogonal cleanups?
- Which files/functions are modified and for what purposes?
- You MUST organize changes by logical purpose rather than by original commit sequence
- You SHOULD read original commit messages when they provide useful context about intent
- You MUST focus on the end state (what the diff accomplishes) rather than the development path
- You SHOULD present a summary of development strands based on the diff analysis and ask if your analysis matches the user's understanding
4. Develop Commit Plan
Create a concrete proposal for the final commit sequence that best meets the established principles, stored as an executable refactoring plan.
Using the development strands identified in step 3, develop a commit plan with the following structure:
Constraints:
- You MUST create a
REFACTORING_PLAN.mdfile in the repository root directory with specific format for recursive execution - You MUST include an "Agent instructions" section that defines how to process each commit
- You MUST include an "Overview" section with a checklist of commits and their main messages
- You MUST include a "Details" section with full specifications for each commit
- You MUST organize commits to follow the agreed-upon principles (e.g., refactorings before behavior changes)
- You MUST ensure each proposed commit has a clear, single purpose within the overall story
- For each commit detail, You MUST specify:
- The complete commit message
- Specific list of files containing relevant changes
- For files with changes from multiple strands, precise guidance on which changes belong to this commit (including diff hunks if necessary)
- Which existing commits or parts of commits are involved
- Concrete instructions that put you in the shoes of the executing agent
- You MUST design the plan so recursive agent invocation can process one commit at a time
- You MUST iterate on the
REFACTORING_PLAN.mdfile with the user until they approve it - You MUST allow the user to edit the plan directly or request modifications
- You MUST NOT proceed to execution until the user explicitly approves the final plan
5. Execute Refactoring Plan
Execute the approved refactoring plan through collaborative delegation using the diff-based approach.
Constraints:
- You MUST ensure you are working on the clean branch created in step 2
- You MUST have the
/tmp/HISTORY_FULL_CHANGES.difffile available as the source of all changes - You MUST execute the plan iteratively using delegation:
- For each uncompleted item in the REFACTORING_PLAN.md checklist:
- Create a
/tmp/HISTORY_DELEGATED_TASK.mdfile with the specific commit task - Recommend running:
kiro-cli chat --non-interactive --trust-all-tools "$(cat /tmp/HISTORY_DELEGATED_TASK.md)" 2>&1 | tee /tmp/HISTORY_DELEGATE.log - Wait for the delegated agent to complete and report results in the file
- Review the results and update the main plan accordingly
- Create a
- Continue until all commits are completed or plan revision is needed
- For each uncompleted item in the REFACTORING_PLAN.md checklist:
- You MUST monitor for execution issues and adapt the plan:
- If a delegated agent reports BLOCKED or NEED_HELP, revise the plan
- If dependencies are discovered, reorder or split commits as needed
- If the current approach isn't working, consider alternative strategies
- You MUST verify the final git history matches the approved plan (as revised)
- You MUST verify that the final state matches the original branch by comparing against
/tmp/HISTORY_FULL_CHANGES.diff - You MUST provide instructions for pushing the cleaned history when complete
File Formats
REFACTORING_PLAN.md Format
The refactoring plan file MUST follow this format:
# Git History Refactoring Plan
## Overview
This plan organizes the git history cleanup for: [PR description]
**Commits to create:**
* [ ] Rename wiz to bang
* [ ] Add hook for customizing bang message
* [ ] Distinguish bang messages based on context
## Commit Details
### 1. Rename wiz to bang
**Complete commit message:**
refactor: rename wiz to bang for clarity
Renames the core wiz functionality to bang to better reflect its purpose in the overall authentication system. This prepares for the upcoming hook system by making the naming more intuitive.
**Diff sections to include:**
- **Lines 15-20 in full-changes.diff**: `WIZ_CONFIG` → `BANG_CONFIG` rename in src/config.js
- **Lines 45-60 in full-changes.diff**: Function rename `validateWiz` → `validateBang` and exports in src/utils/validation.js
- **Exclude**: Do not include the hook mechanism changes (lines 80-95, that belongs to commit 2)
### 2. Add hook for customizing bang message
[Additional commit specifications...]
DELEGATED_TASK.md Format
For each commit, create a delegation file following this format:
# Delegated Task: [Commit Name]
## Context
**Overall PR Goal:** [Brief description from PR context]
**Current Step:** [Which step in the overall plan]
**Previous Commits:** [What has been committed so far]
## Your Mission
Create one commit that accomplishes: [Specific commit goal]
**Target commit message:**
[Full commit message as specified in plan]
## Current State
**Available files:**
- `/tmp/HISTORY_FULL_CHANGES.diff` - Complete diff of all changes from original branch
- Current working directory on clean branch `[clean-branch-name]`
**Your task:** Copy relevant sections from `/tmp/HISTORY_FULL_CHANGES.diff` to `/tmp/HISTORY_TO_STAGE.diff`, apply, and commit
## Expected Changes
**Diff sections to copy:** [Specific line ranges and sections from `/tmp/HISTORY_FULL_CHANGES.diff`]
**Files that should be modified:** [List of files that will change]
## Process
1. **FIRST**: Regenerate the diff to ensure it's current: `git diff [clean-branch-name] [original-branch-name] > /tmp/HISTORY_FULL_CHANGES.diff`
2. Examine `/tmp/HISTORY_FULL_CHANGES.diff` to understand all remaining changes
3. Copy the specified sections from `/tmp/HISTORY_FULL_CHANGES.diff` to `/tmp/HISTORY_TO_STAGE.diff`
4. Apply the patch: `git apply /tmp/HISTORY_TO_STAGE.diff` (or `git apply /tmp/HISTORY_TO_STAGE.diff -- specific/file.js` for large diffs)
5. Verify the changes look correct with `git status` and `git diff`
6. Make small compilation fixes if needed for this commit to build independently
7. Create the commit with the specified message
8. Test that the commit builds correctly (run build/test commands if available)
9. Clean up `/tmp/HISTORY_TO_STAGE.diff` file
10. Report results below
## Troubleshooting
- **For large diffs**: Focus on copying only the sections for files you're actually modifying in this commit
- If `git apply` fails, check that you copied the diff sections correctly and ensure proper formatting
- If you discover unexpected dependencies, report them rather than forcing the commit
- If the specified diff sections don't make sense together, suggest alternative groupings
- If build/compilation fails, try copying additional related sections from `/tmp/HISTORY_FULL_CHANGES.diff`
- When in doubt, ask for help rather than making assumptions
## RESULTS
**Status:** [SUCCESS/NEED_HELP/BLOCKED - fill this in when complete]
**Commits Made:** [List any commits created]
**Issues Encountered:** [Describe any problems]
**Remaining Staged Changes:** [What's left for future commits]
**Suggested Plan Changes:** [Any recommendations for revising the plan]
6. Final Review and Verification
Present the cleaned-up history and verify it meets the storytelling goals.
Constraints:
- You MUST show the final commit history with new messages
- You MUST verify that the story flows logically from commit to commit
- You SHOULD check that refactorings come before related behavior changes
- You MUST confirm that the final state matches the original branch tip
- You SHOULD suggest any remaining improvements to commit organization
- You MUST provide instructions for pushing the cleaned history
- You MUST ask the user what they want to do with the temporary files:
REFACTORING_PLAN.md(the overall plan)/tmp/HISTORY_DELEGATED_TASK.md(the final delegation file)/tmp/HISTORY_FULL_CHANGES.diff(the complete diff file)/tmp/HISTORY_DELEGATE.log(delegation execution log)- Clean branch
[original-branch-name]-[date]-clean
- You MUST NOT commit these planning and diff files to the repository
Examples
Example PR Description
This PR adds OAuth 2.0 authentication to replace our basic username/password system. It maintains backward compatibility during a transition period and includes proper session management.
Example of Good Commit Sequence
1. Extract user validation logic (prepare for OAuth integration)
2. Add OAuth configuration and dependencies
3. Implement OAuth provider authentication flow
4. Add backward compatibility layer for existing auth
5. Update session management for OAuth tokens
6. Add OAuth-specific error handling and logging
Example of Poor Commit Sequence (to be cleaned up)
1. Add OAuth stuff
2. Fix compilation errors
3. More OAuth work
4. Fix tests
5. Actually fix the OAuth implementation
6. Remove debug logging
7. Fix merge conflicts
Troubleshooting
Rebase Conflicts
If conflicts occur during rebase operations, you MUST:
- Pause the rebase process
- Explain the conflict to the user
- Guide them through resolution
- Verify the resolution maintains the intended story flow
Lost Work Recovery
If operations fail and work appears lost:
- Direct the user to the backup branch created in step 2
- Provide commands to restore from backup
- Suggest starting over with smaller, incremental changes