Bluefox Stack

Upgrade engine
for scaffolded apps

Declarative upgrade operations. Conflict detection. Multi-step chains with automatic collapsing. User edits are never silently overwritten.

Define an upgrade
upgrades.py
from bluefox_upgrade import Upgrade, ReplaceFile, BumpDependency

upgrade = Upgrade(
    from_version="0.1.0",
    to_version="0.2.0",
    description="Upgrade to v0.2.0",
    operations=[
        ReplaceFile(path="Dockerfile", template="dockerfile_v2.jinja", description="update base image"),
        BumpDependency(name="fastapi", old_spec=">=0.115", new_spec=">=0.120"),
    ],
)

What you get

Seven operation types

ReplaceFile, CreateFile, RemoveFile, UpdateSection, AddDependency, BumpDependency, RemoveDependency.

Conflict detection

SHA-256 hashing detects user edits. Three conflict modes: abort, skip, or force with automatic backup.

Multi-step chains

Jump from v0.1 to v0.5 in one pass. Redundant operations are automatically collapsed.

Section markers

Update managed sections of files while preserving user code outside # --- bluefox:marker --- blocks.

Format-preserving TOML

Add, bump, and remove dependencies in pyproject.toml without losing comments or formatting.

Automatic backups

Force mode backs up modified files to .bluefox-backups/ before overwriting. Nothing is lost.

Plan, check, execute

The upgrade engine separates planning from execution. Check for conflicts before applying anything.

run_upgrade.py
from bluefox_upgrade import plan_upgrade, check_conflicts, execute_upgrade

# Plan: chain upgrades and collapse redundant ops
plan = plan_upgrade(dotfile, upgrades, target="0.4.0")

# Check: detect files the user has modified
conflicts = check_conflicts(plan, project_dir, dotfile)

# Execute: apply with skip or force
result = execute_upgrade(plan, project_dir, dotfile, render_template,
                         skip_conflicts=True)

print(f"Applied: {len(result.applied)}, Skipped: {len(result.skipped)}")