Skip to content

Ahad690/Upgrade-Code

Repository files navigation

Enterprise Code Upgrader v3

Recursively upgrades all source files in a directory to enterprise quality using Claude Code/OpenCode CLI, maintaining a single conversation so the AI builds context as it goes. Auto-rotates to a new session when context fills up. Commits to a feature branch by default so you review before merging.

What's New in v3

Feature v2 v3
Default backend API (separate billing) Claude Code CLI (free with Pro/Max) or OpenCode (free, no auth, any model)
Git strategy Commits directly to current branch Creates upgrade branch → you review → merge
Session management -c (continue most recent — fragile) --session-id <uuid> (deterministic)
Reasoning depth None --effort max + adaptive thinking (API)
Permission handling --permission-mode (can be overridden) --dangerously-skip-permissions (hard bypass)
Structured output Regex parsing of markdown --json-schema structured JSON
Syntax validation None — broken code gets committed ast.parse() for Python, node --check for JS
Retry on failure Skip and move on Re-prompts with error context (up to 2 retries)
State tracking Injects # ENTERPRISE-UPGRADED into source External .upgrade-state.json — no code pollution
Output sanity check None Rejects responses <40% or >500% of original size
Context management while messages > 42 (arbitrary trim) Token-based: auto-rotates session at 90% full
Context window 200K assumed for all models 1M for opus/sonnet, 200K for everything else
Token tracking None (CLI) Per-call context %, cumulative cost, session count
Batch fallback Parse failure = file skipped Falls back to individual upgrade
Cold start Full init every call --bare skips hooks/LSP/plugins (~2s faster)
Overload resilience Fails --fallback-model sonnet auto-fallback
Hybrid mode N/A Two-pass: Opus plans → Sonnet executes
File exploration N/A Optional --explore with hard read limits

Quick Start

# Upgrade entire backend (CLI is default — free with Pro/Max, no API key needed)
.\upgrade.ps1 -ProjectPath "C:\Users\subha\projects\penora\backend"

# Specific patterns, commit every 5 files
.\upgrade.ps1 -ProjectPath "." -Include "backend/**/*.py" -CommitEvery 5

# Push the upgrade branch to origin (create PR from GitHub UI)
.\upgrade.ps1 -ProjectPath "." -Include "backend/**/*.py" -Push

# Skip branch creation — commit directly to current branch
.\upgrade.ps1 -ProjectPath "." -Include "backend/**/*.py" -Direct

# Custom branch name
.\upgrade.ps1 -ProjectPath "." -Include "backend/**/*.py" -Branch "upgrade/my-feature"

# Stateless mode — no session clutter (trades cross-file context for clean UI)
.\upgrade.ps1 -ProjectPath "." -Include "backend/**/*.py" -NoPersist

# Frontend files
.\upgrade.ps1 -ProjectPath "." -Include "src/**/*.ts","src/**/*.tsx"

# Dry-run (preview in /upgraded/ folder, nothing overwritten)
.\upgrade.ps1 -ProjectPath "." -Include "backend/**/*.py" -DryRun

# Resume after interruption (reads .upgrade-state.json)
.\upgrade.ps1 -ProjectPath "." -Include "**/*.py" -SkipDone

# Start fresh (clear state from previous run)
.\upgrade.ps1 -ProjectPath "." -Include "**/*.py" -ResetState

# Use API backend instead (separate billing, requires ANTHROPIC_API_KEY)
.\upgrade.ps1 -ProjectPath "." -Backend api -ApiKey "sk-ant-..."

# Use OpenCode CLI backend (free, no API key, any model/provider)
.\upgrade.ps1 -ProjectPath "." -Backend opencode -Model "anthropic/claude-sonnet-4-20250514"

# Start from an existing branch instead of HEAD (for incremental upgrades)
.\upgrade.ps1 -ProjectPath "." -FromBranch "upgrade/enterprise-20260404-1958"

# Budget cap for large runs
.\upgrade.ps1 -ProjectPath "." -Include "**/*.py" -MaxBudget 10.00

Hybrid Mode

Two-pass upgrade: a planning model analyzes the file, then an execution model writes the code. Use different models for each pass to balance quality and speed.

# Opus plans, Sonnet executes (recommended)
.\upgrade.ps1 -ProjectPath "." -Include "**/*.py" -Hybrid -Model sonnet -PlanningModel opus

# Same model for both passes (just effort levels differ)
.\upgrade.ps1 -ProjectPath "." -Include "**/*.py" -Hybrid

How it works:

  1. Pass 1 (Planning): The planning model (default: same as --model, or --planning-model override) analyzes the file with high effort and produces a numbered improvement plan. No code is written.
  2. Pass 2 (Execution): The execution model (--model) receives the plan and the file, then writes the complete upgraded code.

Effort levels are capped automatically: max is Opus-only, Sonnet caps at high.

File Exploration

By default, the AI works only with the file content provided — no tools, no file reads. This keeps context lean and upgrades fast.

With --explore, the AI gets Read access to the project so it can check imports, shared types, and interfaces before upgrading:

# Explore with defaults (max 5 reads per file, cutoff at 500k context)
.\upgrade.ps1 -ProjectPath "." -Include "**/*.py" -Explore

# Allow up to 10 reads per file
.\upgrade.ps1 -ProjectPath "." -Include "**/*.py" -Explore -MaxReads 10

# Very conservative: 2 reads per file
.\upgrade.ps1 -ProjectPath "." -Include "**/*.py" -Explore -MaxReads 2

# Hybrid + explore (only the planning pass gets Read access)
.\upgrade.ps1 -ProjectPath "." -Include "**/*.py" -Hybrid -PlanningModel opus -Model sonnet -Explore -MaxReads 5

Two hard limits prevent runaway context growth:

Limit Mechanism Effect
--max-reads N (default 5) --max-turns N+1 passed to CLI After N file reads, the CLI forcibly stops the agentic loop
Context > 500k tokens Read tool revoked (--tools "") Once session accumulates 500k tokens, explore is disabled for all subsequent calls

Both limits reset per file. In hybrid mode, only the planning pass gets Read access — the execution pass never explores.

When --explore is off, the agent gets --tools "" (no tools at all). This is a hard CLI-level enforcement, not a prompt instruction.

How It Works

┌──────────────────────────────────────────────────────────────────┐
│                                                                  │
│  git checkout -b upgrade/enterprise-20250324-1430                │
│                                                                  │
│  Session #1 (opus/sonnet = 1M token context)                     │
│                                                                  │
│  1. Send project overview + file manifest                        │
│  2. Send auth.py → get upgraded auth.py                          │
│     → validate syntax (ast.parse) ✓                              │
│     → sanity check size ✓                                        │
│     → write file + commit to upgrade branch                      │
│     → log: "Context: 45,000 / 1,000,000 tokens (5%)"            │
│                                                                  │
│  3. Send users.py → upgraded (uses auth.py context)              │
│     → syntax error! → retry with error message                   │
│     → 2nd attempt passes ✓ → write + commit                     │
│                                                                  │
│  ... 40 more files ...                                           │
│                                                                  │
│  44. Context: 910,000 / 1,000,000 (91%)                         │
│      ⟳ SESSION ROTATED → #2 (fresh context + system prompt)      │
│                                                                  │
│  Session #2                                                      │
│  45. Send routes.py → upgraded (patterns from system prompt)     │
│     → log: "Context: 35,000 / 1,000,000 tokens (4%)"            │
│                                                                  │
│  ... continues until all files done ...                          │
│                                                                  │
│  git push -u origin upgrade/enterprise-20250324-1430  (if --push)│
│  git checkout main  (switch back)                                │
│                                                                  │
│  → You review the branch, create a PR, merge when satisfied      │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘

All Options

Flag Default Description
Files
--include **/*.* Glob patterns for files
--exclude smart defaults Extra patterns to skip
Backend
--backend cli cli (Claude Code CLI, free), api (Anthropic API, separate billing), or opencode (OpenCode CLI — free, no auth, any model/provider)
--model opus (CLI) / claude-opus-4-6 (API) / opencode/qwen3.6-plus-free (OpenCode) Model for code execution
--planning-model same as --model Model for planning pass in --hybrid mode (e.g. opus)
--effort max Reasoning depth: low, medium, high, max (max is Opus-only, Sonnet caps at high)
--fallback-model sonnet Auto-fallback when primary model is overloaded
--max-budget unlimited Max USD to spend (CLI backend)
--no-persist off Stateless: no session saved (clean UI, no cross-file context)
--no-json-schema off Disable structured output (use markdown regex parsing)
Hybrid Mode
--hybrid off Two-pass: planning pass (high effort) → execution pass. Doubles CLI calls per file.
--planning-model same as --model Model for the planning pass (e.g. opus while --model sonnet)
Exploration
--explore off Allow AI to Read related project files for context before upgrading
--max-reads 5 Max files the AI can Read per file upgrade (enforced via --max-turns at CLI level)
--no-explore-cutoff off Disable the 500k token auto-revoke of Read tool — explore keeps working regardless of context size
Git
--branch auto Create upgrade branch (auto-named upgrade/enterprise-YYYYMMDD-HHMM). Pass a name to override.
--direct off Skip branch creation, commit to current branch. Not recommended for production.
--from-branch off Create upgrade branch from an existing branch (e.g. --from-branch upgrade/enterprise-20260404-1958). Enables linear upgrade chains across runs.
--push off Push upgrade branch to origin after completion.
--commit-every 1 Git commit after every N files
--no-commit off Disable git commits
Processing
--no-batch off Process every file individually
--batch-size 3 Small files per batch prompt
--dry-run off Save to /upgraded/ instead of overwriting
--delay 2.0 Seconds between calls
State
--skip-done off Skip files in .upgrade-state.json
--reset-state off Clear state file and start fresh
--system-prompt system_prompt.md Custom system prompt file

Git Branching Strategy

By default, the upgrader creates a feature branch before making any changes:

main ──●──────────────────────────────●── (untouched)
        \                            /
         upgrade/enterprise-... ──●──●──●──●── (all upgrades here)
Mode Command Behavior
Branch (default) .\upgrade.ps1 -ProjectPath . Creates branch, commits there, switches back to original when done
Branch + push .\upgrade.ps1 -ProjectPath . -Push Same + pushes branch to origin (create PR from GitHub UI)
Custom branch .\upgrade.ps1 -ProjectPath . -Branch "upgrade/v2" Your branch name instead of auto-generated
Direct .\upgrade.ps1 -ProjectPath . -Direct Old behavior: commits to current branch (no branch creation)

After completion, the summary shows your next steps:

============================================================
  DONE — 47/50 upgraded, 3 failed
  Tokens: 2,450,000 | Context: 34% of 1000K | Sessions: 3
  Branch: upgrade/enterprise-20250324-1430 (local only)
  Push:   git push -u origin upgrade/enterprise-20250324-1430
  Merge:  git checkout main && git merge upgrade/enterprise-20250324-1430
  Or PR:  create pull request from upgrade/enterprise-20250324-1430 → main
============================================================

Validation Pipeline

Every upgraded file passes through 3 checks before being written:

  1. Parse check — Can the code be extracted from the LLM response? (JSON schema or regex on markdown code blocks)
  2. Sanity check — Is the output between 40%–500% of the original size? (catches truncation and hallucination)
  3. Syntax check — Does it parse? Python: ast.parse(). JavaScript: node --check. Others: skipped.

If any check fails, the file is re-prompted with the specific error. Up to 2 retries. If all fail, the file is marked as failed in .upgrade-state.json and the raw response is saved to .upgrade-debug/ for manual review.

Context Management

The source of truth is total context tokensinput_tokens + cache_creation_input_tokens + cache_read_input_tokens from the API response. This is the actual context the model processes per call, including cached portions.

Model Context Window ~Files per session
opus / sonnet 1,000,000 tokens ~80-120 files
Everything else 200,000 tokens ~15-25 files

Auto-rotation at 90%: When context tokens >= 90% of limit, the upgrader generates a new session ID. The next call starts a fresh conversation with the system prompt re-sent. Cross-file context is lost, but the system prompt carries all the architectural patterns.

Session recovery: If a CLI call times out, the session ID may be tainted. The upgrader auto-recovers by either regenerating a fresh UUID or switching to --resume mode for the existing session.

Log output during a run:

14:30:35  INFO     Context: 45,231 / 1,000,000 tokens (5%)
...
15:12:44  WARNING      Context 78% full — approaching rotation threshold
...
15:45:02  WARNING      ⟳ SESSION ROTATED → #2 (was 91% full, old=a3f2b1c8…, new=7e4d9f12…)

Final summary:

  Tokens: 2,450,000 (in: 2,100,000, out: 350,000) | Cost: $4.21 | Context: 34% of 1000K | Sessions: 3

State Management

State is tracked in .upgrade-state.json at the project root:

{
  "completed": {
    "backend/auth.py": {
      "timestamp": "2025-03-24T14:30:00",
      "changes": "- Added typed exception hierarchy\n- Extracted config dataclass",
      "original_lines": 120,
      "upgraded_lines": 340
    }
  },
  "failed": {
    "backend/legacy.py": "Syntax error after 2 retries: unexpected indent at line 45"
  },
  "started_at": "2025-03-24T14:00:00",
  "last_updated": "2025-03-24T14:30:00"
}

File Structure

your-project/
├── .upgrade-state.json      # Progress tracking (resume-safe)
├── .upgrade-logs/           # Change summaries (one per file)
│   ├── backend__auth_changes.md
│   └── ...
├── .upgrade-debug/          # Raw LLM responses (only on failures)
│   └── legacy_raw.txt
└── (your upgraded source files)

Tips

  1. Start with --dry-run to review before overwriting
  2. Use --skip-done to resume interrupted runs — reads .upgrade-state.json
  3. Commit your work first before running without --dry-run
  4. Use --push to push the upgrade branch and create a PR from the GitHub UI
  5. Use --direct only when you've already created a branch manually
  6. Use --commit-every 5 for cleaner git history
  7. Edit system_prompt.md to add project-specific patterns
  8. Check .upgrade-debug/ when files fail — the raw LLM response is there
  9. Use --reset-state to re-process files that were previously completed
  10. Use --no-persist if you don't want upgrader sessions cluttering your Claude Code session list
  11. For huge codebases (100+ files), the auto-rotation handles context overflow automatically
  12. Use --max-budget 5.00 to cap spend on large runs
  13. Use --hybrid -PlanningModel opus -Model sonnet for best quality/speed balance
  14. Use --explore -MaxReads 3 when the AI needs to understand shared types and interfaces
  15. Use --backend opencode for a free backend with no API key — any model via provider/model format (e.g. anthropic/claude-sonnet-4-20250514, google/gemini-2.5-pro, openai/gpt-5.4)
  16. Use --from-branch to chain upgrades incrementally — start from the branch of a previous run and pick up where you left off
  17. OpenCode uses regex parsing (no --json-schema support) and auto-approves all permissions by default

About

Automate upgrading your code files to enterprise level if you have a Claude Code Subscription or API.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors