## Semantic Commit Breaks big changes into small, meaningful commits with proper messages. Uses only standard git commands. ### Usage ```bash /semantic-commit [options] ``` ### Options - `--dry-run`: Show proposed commit splits without actually committing - `--lang `: Force language for commit messages (en) - `--max-commits `: Specify maximum number of commits (default: 10) ### Basic Examples ```bash # Analyze current changes and commit in logical units /semantic-commit # Check split proposal only (no actual commit) /semantic-commit --dry-run # Generate commit messages in English /semantic-commit --lang en # Split into maximum 5 commits /semantic-commit --max-commits 5 ``` ### How It Works 1. **Analyze Changes**: Check what changed with `git diff HEAD` 2. **Group Files**: Put related files together 3. **Create Messages**: Write semantic commit messages for each group 4. **Commit Step by Step**: Commit each group after you approve ### When to Split Changes #### What Makes a Change "Large" We split when we see: 1. **Many Files**: 5+ files changed 2. **Many Lines**: 100+ lines changed 3. **Multiple Features**: Changes in 2+ areas 4. **Mixed Types**: feat + fix + docs together ```bash # Analyze change scale CHANGED_FILES=$(git diff HEAD --name-only | wc -l) CHANGED_LINES=$(git diff HEAD --stat | tail -1 | grep -o '[0-9]\+ insertions\|[0-9]\+ deletions' | awk '{sum+=$1} END {print sum}') if [ $CHANGED_FILES -ge 5 ] || [ $CHANGED_LINES -ge 100 ]; then echo "Large change detected: splitting recommended" fi ``` #### How to Split into Small, Meaningful Commits ##### 1. Splitting by Functional Boundaries ```bash # Identify functional units from directory structure git diff HEAD --name-only | cut -d'/' -f1-2 | sort | uniq # → src/auth, src/api, components/ui, etc. ``` ##### 2. Separation by Change Type ```bash # New files vs existing file modifications git diff HEAD --name-status | grep '^A' # New files git diff HEAD --name-status | grep '^M' # Modified files git diff HEAD --name-status | grep '^D' # Deleted files ``` ##### 3. Dependency Analysis ```bash # Detect import relationship changes git diff HEAD | grep -E '^[+-].*import|^[+-].*require' | \ cut -d' ' -f2- | sort | uniq ``` #### Detailed File Analysis ```bash # Get list of changed files git diff HEAD --name-only # Analyze each file's changes individually git diff HEAD -- # Determine change type for files git diff HEAD --name-status | while read status file; do case $status in A) echo "$file: New creation" ;; M) echo "$file: Modification" ;; D) echo "$file: Deletion" ;; R*) echo "$file: Renamed" ;; esac done ``` #### How to Group Files 1. **By Feature**: Keep related functions together - `src/auth/` files → Authentication - `components/` files → UI components 2. **By Type**: Same kind of changes - Only tests → `test:` - Only docs → `docs:` - Only config → `chore:` 3. **By Dependencies**: Files that need each other - Model + Migration - Component + Style 4. **By Size**: Keep commits manageable - Max 10 files per commit - Keep related files together ### Output Example ```bash $ /semantic-commit Analyzing changes... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Detected changes: • src/auth/login.ts (modified) • src/auth/register.ts (new) • src/auth/types.ts (modified) • tests/auth.test.ts (new) • docs/authentication.md (new) Proposed commit splits: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Commit 1/3 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Message: feat: implement user registration and login system Included files: • src/auth/login.ts • src/auth/register.ts • src/auth/types.ts ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Commit 2/3 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Message: test: add comprehensive tests for authentication system Included files: • tests/auth.test.ts ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Commit 3/3 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Message: docs: add authentication system documentation Included files: • docs/authentication.md Execute commit with this split plan? (y/n/edit): ``` ### Your Options - `y`: Go with the proposed split - `n`: Cancel everything - `edit`: Change commit messages - `merge `: Combine commits - `split `: Break up a commit more ### Dry Run Mode ```bash $ /semantic-commit --dry-run Analyzing changes... (DRY RUN) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [Commit split proposal display] ℹ️ DRY RUN mode: No actual commits will be executed 💡 To execute, run again without --dry-run option ``` ### Smart Features #### 1. Understands Your Project - Detects project type from config files - Figures out features from folder structure #### 2. Change Pattern Recognition ```bash # Detect bug fix patterns - Keywords like "fix", "bug", "error" - Addition of exception handling - Condition branch fixes # Detect new feature patterns - New file creation - New method additions - API endpoint additions ``` #### 3. Dependency Analysis - Changes to import statements - Addition/modification of type definitions - Relationship with configuration files ### How It's Built #### Step-by-Step Commits with Git ##### 1. Preprocessing: Save Current State ```bash # Reset unstaged changes if any git reset HEAD git status --porcelain > /tmp/original_state.txt # Check working branch CURRENT_BRANCH=$(git branch --show-current) echo "Working branch: $CURRENT_BRANCH" ``` ##### 2. Sequential Commit Execution by Group ```bash # Read split plan while IFS= read -r commit_plan; do group_num=$(echo "$commit_plan" | cut -d':' -f1) files=$(echo "$commit_plan" | cut -d':' -f2- | tr ' ' '\n') echo "=== Executing commit $group_num ===" # Stage only relevant files echo "$files" | while read file; do if [ -f "$file" ]; then git add "$file" echo "Staged: $file" fi done # Check staging status staged_files=$(git diff --staged --name-only) if [ -z "$staged_files" ]; then echo "Warning: No files staged" continue fi # Generate commit message (LLM analysis) commit_msg=$(generate_commit_message_for_staged_files) # User confirmation echo "Proposed commit message: $commit_msg" echo "Staged files:" echo "$staged_files" read -p "Execute this commit? (y/n): " confirm if [ "$confirm" = "y" ]; then # Execute commit git commit -m "$commit_msg" echo "✅ Commit $group_num completed" else # Cancel staging git reset HEAD echo "❌ Skipped commit $group_num" fi done < /tmp/commit_plan.txt ``` ##### 3. Error Handling and Rollback ```bash # Handle pre-commit hook failures commit_with_retry() { local commit_msg="$1" local max_retries=2 local retry_count=0 while [ $retry_count -lt $max_retries ]; do if git commit -m "$commit_msg"; then echo "✅ Commit successful" return 0 else echo "❌ Commit failed (attempt $((retry_count + 1))/$max_retries)" # Incorporate automatic fixes from pre-commit hooks if git diff --staged --quiet; then echo "Changes automatically fixed by pre-commit hook" git add -u fi retry_count=$((retry_count + 1)) fi done echo "❌ Failed to commit. Please check manually." return 1 } # Recover from interruptions resume_from_failure() { echo "Detected interrupted commit process" echo "Current staging status:" git status --porcelain read -p "Continue processing? (y/n): " resume if [ "$resume" = "y" ]; then # Resume from last commit last_commit=$(git log --oneline -1 --pretty=format:"%s") echo "Last commit: $last_commit" else # Full reset git reset HEAD echo "Process reset" fi } ``` ##### 4. Post-Completion Verification ```bash # Verify all changes committed remaining_changes=$(git status --porcelain | wc -l) if [ $remaining_changes -eq 0 ]; then echo "✅ All changes committed" else echo "⚠️ Uncommitted changes remain:" git status --short fi # Display commit history echo "Created commits:" git log --oneline -n 10 --graph ``` ##### 5. Suppress Automatic Push ```bash # Note: No automatic push echo "📝 Note: Automatic push not performed" echo "If needed, push with the following command:" echo " git push origin $CURRENT_BRANCH" ``` #### Split Algorithm Details ##### Step 1: Initial Analysis ```bash # Get and classify all changed files git diff HEAD --name-status | while read status file; do echo "$status:$file" done > /tmp/changes.txt # Statistics of changes by functional directory git diff HEAD --name-only | cut -d'/' -f1-2 | sort | uniq -c ``` ##### Step 2: Initial Grouping by Functional Boundaries ```bash # Directory-based grouping GROUPS=$(git diff HEAD --name-only | cut -d'/' -f1-2 | sort | uniq) for group in $GROUPS; do echo "=== Group: $group ===" git diff HEAD --name-only | grep "^$group" | head -10 done ``` ##### Step 3: Analyzing Change Similarity ```bash # Analyze change type for each file git diff HEAD --name-only | while read file; do # Detect new function/class additions NEW_FUNCTIONS=$(git diff HEAD -- "$file" | grep -c '^+.*function\|^+.*class\|^+.*def ') # Detect bug fix patterns BUG_FIXES=$(git diff HEAD -- "$file" | grep -c '^+.*fix\|^+.*bug\|^-.*error') # Determine if test file if [[ "$file" =~ test|spec ]]; then echo "$file: TEST" elif [ $NEW_FUNCTIONS -gt 0 ]; then echo "$file: FEAT" elif [ $BUG_FIXES -gt 0 ]; then echo "$file: FIX" else echo "$file: REFACTOR" fi done ``` ##### Step 4: Dependency-based Adjustments ```bash # Analyze import relationships git diff HEAD | grep -E '^[+-].*import|^[+-].*from.*import' | \ while read line; do echo "$line" | sed 's/^[+-]//' | awk '{print $2}' done | sort | uniq > /tmp/imports.txt # Group related files git diff HEAD --name-only | while read file; do basename=$(basename "$file" .js .ts .py) related=$(git diff HEAD --name-only | grep "$basename" | grep -v "^$file$") if [ -n "$related" ]; then echo "Related files: $file <-> $related" fi done ``` ##### Step 5: Commit Size Optimization ```bash # Adjust group size MAX_FILES_PER_COMMIT=8 current_group=1 file_count=0 git diff HEAD --name-only | while read file; do if [ $file_count -ge $MAX_FILES_PER_COMMIT ]; then current_group=$((current_group + 1)) file_count=0 fi echo "Commit $current_group: $file" file_count=$((file_count + 1)) done ``` ##### Step 6: Determining Final Groups ```bash # Verify split results for group in $(seq 1 $current_group); do files=$(grep "Commit $group:" /tmp/commit_plan.txt | cut -d':' -f2-) lines=$(echo "$files" | xargs git diff HEAD -- | wc -l) echo "Commit $group: $(echo "$files" | wc -w) files, $lines lines changed" done ``` ### Conventional Commits Compliance #### Basic Format ```text [optional scope]: [optional body] [optional footer(s)] ``` #### Standard Types **Required Types**: - `feat`: New feature (user-visible feature addition) - `fix`: Bug fix **Optional Types**: - `build`: Changes to build system or external dependencies - `chore`: Other changes (no impact on release) - `ci`: Changes to CI configuration files or scripts - `docs`: Documentation-only changes - `style`: Changes that do not affect code meaning (whitespace, formatting, semicolons, etc.) - `refactor`: Code changes without bug fixes or feature additions - `perf`: Performance improvements - `test`: Adding or modifying tests #### Scope (Optional) Indicates the affected area of the change: ```text feat(api): add user authentication endpoint fix(ui): resolve button alignment issue docs(readme): update installation instructions ``` #### Breaking Change When there are breaking API changes: ```text feat!: change user API response format ``` or ```text feat(api)!: change authentication flow ``` #### Automatically Detecting Project Conventions **Important**: If project-specific conventions exist, they take precedence. ##### 1. Check CommitLint Configuration Automatically detect configuration from the following files: - `commitlint.config.js` - `commitlint.config.mjs` - `commitlint.config.cjs` - `commitlint.config.ts` - `.commitlintrc.js` - `.commitlintrc.json` - `.commitlintrc.yml` - `.commitlintrc.yaml` - `commitlint` section in `package.json` ```bash # Check example configuration files cat commitlint.config.mjs cat .commitlintrc.json grep -A 10 '"commitlint"' package.json ``` ##### 2. Detecting Custom Types Example of project-specific types: ```javascript // commitlint.config.mjs export default { extends: ["@commitlint/config-conventional"], rules: { "type-enum": [ 2, "always", [ "feat", "fix", "docs", "style", "refactor", "test", "chore", "wip", // Work in progress "hotfix", // Emergency fix "release", // Release "deps", // Dependency update "config", // Configuration change ], ], }, }; ``` ##### 3. Detecting Language Settings ```javascript // When project uses Japanese messages export default { rules: { "subject-case": [0], // Disable for Japanese support "subject-max-length": [2, "always", 72], // Adjust character limit for Japanese }, }; ``` #### Automatic Analysis Flow 1. **Configuration File Search** ```bash find . -name "commitlint.config.*" -o -name ".commitlintrc.*" | head -1 ``` 2. **Existing Commit Analysis** ```bash git log --oneline -50 --pretty=format:"%s" ``` 3. **Type Usage Statistics** ```bash git log --oneline -100 --pretty=format:"%s" | \ grep -oE '^[a-z]+(\([^)]+\))?' | \ sort | uniq -c | sort -nr ``` #### Examples of Project Conventions ##### Angular Style ```text feat(scope): add new feature fix(scope): fix bug docs(scope): update documentation ``` ##### Gitmoji Combined Style ```text ✨ feat: add user registration 🐛 fix: resolve login issue 📚 docs: update API docs ``` ##### Japanese Projects ```text feat: add user registration functionality fix: resolve login process bug docs: update API documentation ``` ### Language Detection How we figure out your language: 1. **Check CommitLint Settings** for language configuration ```bash # Determine Japanese if subject-case rule is disabled grep -E '"subject-case".*\[0\]|subject-case.*0' commitlint.config.* ``` 2. **Git log analysis** for automatic determination ```bash # Analyze language of last 20 commits git log --oneline -20 --pretty=format:"%s" | \ grep -E '^[\x{3040}-\x{30ff}]|[\x{4e00}-\x{9fff}]' | wc -l # Japanese mode if over 50% are Japanese ``` 3. **Project files** language settings ```bash # Check README.md language head -10 README.md | grep -E '^[\x{3040}-\x{30ff}]|[\x{4e00}-\x{9fff}]' | wc -l # Check package.json description grep -E '"description".*[\x{3040}-\x{30ff}]|[\x{4e00}-\x{9fff}]' package.json ``` 4. **Comments and strings** analysis in changed files ```bash # Check comment language in changed files git diff HEAD | grep -E '^[+-].*//.*[\x{3040}-\x{30ff}]|[\x{4e00}-\x{9fff}]' | wc -l ``` #### Determination Algorithm ```bash # English version always uses English LANGUAGE="en" ``` ### Auto-Loading Config #### What Happens at Runtime We check for config files in this order: 1. **Search for CommitLint configuration files** ```bash # Search in this order, use first found file commitlint.config.mjs commitlint.config.js commitlint.config.cjs commitlint.config.ts .commitlintrc.js .commitlintrc.json .commitlintrc.yml .commitlintrc.yaml package.json (commitlint section) ``` 2. **Parse configuration content** - Extract list of available types - Check for scope restrictions - Get message length limits - Check language settings 3. **Analyze existing commit history** ```bash # Learn usage patterns from recent commits git log --oneline -100 --pretty=format:"%s" | \ head -20 ``` #### Analyzing Configuration Examples **Standard commitlint.config.mjs**: ```javascript export default { extends: ["@commitlint/config-conventional"], rules: { "type-enum": [ 2, "always", ["feat", "fix", "docs", "style", "refactor", "perf", "test", "chore"], ], "scope-enum": [2, "always", ["api", "ui", "core", "auth", "db"]], }, }; ``` **Japanese-compatible configuration**: ```javascript export default { extends: ["@commitlint/config-conventional"], rules: { "subject-case": [0], // Disable for Japanese "subject-max-length": [2, "always", 72], "type-enum": [ 2, "always", ["feat", "fix", "docs", "style", "refactor", "test", "chore"], ], }, }; ``` **Configuration with custom types**: ```javascript export default { extends: ["@commitlint/config-conventional"], rules: { "type-enum": [ 2, "always", [ "feat", "fix", "docs", "style", "refactor", "test", "chore", "wip", // Work in Progress "hotfix", // Emergency fix "release", // Release preparation "deps", // Dependency update "config", // Configuration change ], ], }, }; ``` #### Fallback Behavior If no configuration file is found: 1. **Automatic inference** through git log analysis ```bash # Extract types from last 100 commits git log --oneline -100 --pretty=format:"%s" | \ grep -oE '^[a-z]+(\([^)]+\))?' | \ sort | uniq -c | sort -nr ``` 2. **Default to Conventional Commits standard** ``` feat, fix, docs, style, refactor, perf, test, chore, build, ci ``` 3. **Language determination** - Japanese mode if over 50% of commits are in Japanese - English mode otherwise ### Requirements - Must be in a Git repo - Need uncommitted changes - Staged changes get reset temporarily ### Important - **Won't push**: You need to `git push` yourself - **Same branch**: Commits stay in current branch - **Back up first**: Consider `git stash` for safety ### Which Rules Win When making commit messages, we follow this order: 1. **CommitLint settings** (highest priority) - Settings in `commitlint.config.*` files - Custom types and scope restrictions - Message length and case restrictions 2. **Existing commit history** (second priority) - Statistics of actually used types - Message language (Japanese/English) - Scope usage patterns 3. **Project type** (third priority) - `package.json` → Node.js project - `Cargo.toml` → Rust project - `pom.xml` → Java project 4. **Conventional Commits standard** (fallback) - Standard behavior when no settings found #### Examples of Convention Detection **Automatic scope detection in Monorepo**: ```bash # Infer scopes from packages/ folder ls packages/ | head -10 # → Propose api, ui, core, auth, etc. as scopes ``` **Framework-specific conventions**: ```javascript // For Angular projects { 'scope-enum': [2, 'always', [ 'animations', 'common', 'core', 'forms', 'http', 'platform-browser', 'platform-server', 'router', 'service-worker', 'upgrade' ]] } // For React projects { 'scope-enum': [2, 'always', [ 'components', 'hooks', 'utils', 'types', 'styles', 'api' ]] } ``` **Company/team-specific conventions**: ```javascript // Common pattern in Japanese companies { 'type-enum': [2, 'always', [ 'feat', 'fix', 'docs', 'style', 'refactor', 'test', 'chore', 'wip', // Work in progress (for pull requests) 'hotfix', // Emergency fix 'release' // Release preparation ]], 'subject-case': [0], // Support Japanese 'subject-max-length': [2, 'always', 72] // Longer limit for Japanese } ``` ### Best Practices 1. **Follow the rules**: Use existing patterns 2. **Keep it small**: One logical change per commit 3. **Be clear**: Say what changed 4. **Group smart**: Related files together 5. **Tests separate**: Test commits on their own 6. **Use configs**: CommitLint helps teams stay consistent ### Real-world Split Examples (Before/After) #### Example 1: Large Authentication System Addition **Before (one massive commit):** ```bash # Changed files (15 files, 850 lines changed) src/auth/login.js # New src/auth/register.js # New src/auth/password.js # New src/auth/types.js # New src/api/auth-routes.js # New src/middleware/auth.js # New src/database/migrations/001_users.sql # New src/database/models/user.js # New tests/auth/login.test.js # New tests/auth/register.test.js # New tests/api/auth-routes.test.js # New docs/authentication.md # New package.json # Dependency addition README.md # Usage addition .env.example # Environment variable example # Problematic conventional commit feat: implement complete user authentication system with login, registration, password reset, API routes, database models, tests and documentation ``` **After (split into 5 meaningful commits):** ```bash # Commit 1: Database foundation feat(db): add user model and authentication schema Included files: - src/database/migrations/001_users.sql - src/database/models/user.js - src/auth/types.js Reason: Database structure is the foundation for other features, committed first # Commit 2: Authentication logic feat(auth): implement core authentication functionality Included files: - src/auth/login.js - src/auth/register.js - src/auth/password.js - src/middleware/auth.js Reason: Core authentication business logic committed together # Commit 3: API endpoints feat(api): add authentication API routes Included files: - src/api/auth-routes.js Reason: API layer depends on authentication logic, committed later # Commit 4: Comprehensive tests test(auth): add comprehensive authentication tests Included files: - tests/auth/login.test.js - tests/auth/register.test.js - tests/api/auth-routes.test.js Reason: Tests added after implementation is complete # Commit 5: Documentation and configuration docs(auth): add authentication documentation and configuration Included files: - docs/authentication.md - package.json - README.md - .env.example Reason: Documentation and configuration committed together at the end ``` #### Example 2: Mixed Bug Fixes and Refactoring **Before (problematic mixed commit):** ```bash # Changed files (8 files, 320 lines changed) src/user/service.js # Bug fixes + Refactoring src/user/validator.js # New (refactoring) src/auth/middleware.js # Bug fix src/api/user-routes.js # Bug fix + Error handling improvement tests/user.test.js # Test addition tests/auth.test.js # Bug fix test addition docs/user-api.md # Documentation update package.json # Dependency update # Problematic commit fix: resolve user validation bugs and refactor validation logic with improved error handling ``` **After (split into 3 commits by type):** ```bash # Commit 1: Critical bug fixes fix: resolve user validation and authentication bugs Included files: - src/user/service.js (bug fix portion only) - src/auth/middleware.js - tests/auth.test.js (bug fix tests only) Reason: Production-affecting bugs fixed with highest priority # Commit 2: Validation logic refactoring refactor: extract and improve user validation logic Included files: - src/user/service.js (refactoring portion) - src/user/validator.js - src/api/user-routes.js - tests/user.test.js Reason: Structural improvements committed as functional units # Commit 3: Documentation and dependency update chore: update documentation and dependencies Included files: - docs/user-api.md - package.json Reason: Development environment improvements committed together at the end ``` #### Example 3: Simultaneous Development of Multiple Features **Before (cross-functional massive commit):** ```bash # Changed files (12 files, 600 lines changed) src/user/profile.js # New feature A src/user/avatar.js # New feature A src/notification/email.js # New feature B src/notification/sms.js # New feature B src/api/profile-routes.js # New feature A API src/api/notification-routes.js # New feature B API src/dashboard/widgets.js # New feature C src/dashboard/charts.js # New feature C tests/profile.test.js # New feature A tests tests/notification.test.js # New feature B tests tests/dashboard.test.js # New feature C tests package.json # All features' dependencies # Problematic commit feat: add user profile management, notification system and dashboard widgets ``` **After (split into 4 commits by feature):** ```bash # Commit 1: User profile feature feat(profile): add user profile management Included files: - src/user/profile.js - src/user/avatar.js - src/api/profile-routes.js - tests/profile.test.js Reason: Profile feature is an independent functional unit # Commit 2: Notification system feat(notification): implement email and SMS notifications Included files: - src/notification/email.js - src/notification/sms.js - src/api/notification-routes.js - tests/notification.test.js Reason: Notification feature is an independent functional unit # Commit 3: Dashboard widgets feat(dashboard): add interactive widgets and charts Included files: - src/dashboard/widgets.js - src/dashboard/charts.js - tests/dashboard.test.js Reason: Dashboard feature is an independent functional unit # Commit 4: Dependencies and infrastructure update chore: update dependencies for new features Included files: - package.json Reason: Common dependency updates committed together at the end ``` ### Comparison of Splitting Effects | Item | Before (Massive Commit) | After (Proper Splitting) | | ------------------------ | ----------------------------------------- | ---------------------------------------------------- | | **Reviewability** | ❌ Very difficult | ✅ Each commit is small and reviewable | | **Bug Tracking** | ❌ Difficult to identify problem location | ✅ Problematic commits can be immediately identified | | **Reverting** | ❌ Need to revert everything | ✅ Can pinpoint and revert only problematic parts | | **Parallel Development** | ❌ Conflict-prone | ✅ Feature-based merging is easy | | **Deployment** | ❌ All features deployed at once | ✅ Staged deployment possible | ### Troubleshooting #### When Commit Fails - Check pre-commit hooks - Resolve dependencies - Retry with individual files #### When Splitting is Inappropriate - Adjust with `--max-commits` option - Use manual `edit` mode - Re-run with finer granularity