# Safe Large Refactors with Snapshots

In this tutorial, we'll show you how to use mng snapshot feature to make large refactors less risky.

Imagine you're doing a large code refactor. The first step looks good, so you step away to go eat food. 20 minutes later it has rewritten half the codebase in a direction that doesn't work. At that point, `git reset` gets you back to clean files, but not back to the exact environment state the agent was working in.

`mng` snapshots give you something better: a full filesystem checkpoint of the agent's host, taken at any point during the work. If the migration goes wrong, you can fork the code. You spin up a fresh agent from the snapshot and try a different approach, while keeping the original run intact in case you want to compare.

This page walks through a concrete example of migrating a Flask REST API to FastAPI.

***

## The scenario

We're working with [flask-realworld-example-app](https://github.com/gothinkster/flask-realworld-example-app), a medium-sized Flask REST API. The goal is to migrate it to FastAPI.

mng's snapshots only work on remote (cloud) hosts, so we'll run this on [Modal](https://gitlab.com/generally-intelligent/mng/-/blob/main/concepts/providers.md).

***

## Step 1: Launch the agent on Modal

```bash
mng create flask-migration@.modal \
  --no-connect \
  --message "I'm going to give you a task in a moment. First, just confirm you're ready."
```

The `@.modal` suffix tells `mng` to provision a new Modal sandbox for this agent. `--no-connect` lets it start in the background, so you don't need to watch the launch sequence.

***

## Step 2: Snapshot before the risky work starts

Once the agent is running and has confirmed it's ready, take a snapshot before sending the real task:

```bash
SNAP=$(mng snapshot create flask-migration --name before-migration --format "{snapshot_id}")
echo $SNAP
# snap-a1b2c3d4
```

The `--format "{snapshot_id}"` flag captures just the ID into a shell variable. You'll need this later.

**Where does the snapshot live?**

Snapshots are stored by the cloud provider, so in this case it's Modal. `mng` doesn't copy anything to your local machine. The snapshot is a complete filesystem image of the host: the working directory, installed packages, environment variables, tool caches, tmux session state, everything. It's not a git commit. It's a full disk checkpoint.

You can list snapshots at any time:

```bash
mng snapshot list flask-migration
# SNAPSHOT ID     NAME                CREATED              SIZE
# snap-a1b2c3d4   before-migration    2024-01-15 14:32:01  4.2 GB
```

***

## Step 3: Send the agent the actual task

```bash
mng message flask-migration "Migrate this Flask app to FastAPI. Replace all Flask route decorators with FastAPI equivalents, convert SQLAlchemy models to use Pydantic schemas, and update the entry point. Make sure the tests still pass when you're done."
```

The agent starts working. You can connect to watch it live:

```bash
mng connect flask-migration
```

Or leave it running and check back later.

***

## Step 4: If it goes wrong, fork from the snapshot

Say the agent decided to rewrite the database layer from scratch instead of just updating the routes, which is not what you wanted. Rather than trying to unwind its changes or running `git reset`, you fork from the snapshot:

```bash
mng create flask-migration-v2@.modal \
  --snapshot $SNAP \
  --message "Migrate this Flask app to FastAPI. Keep the SQLAlchemy models exactly as-is — only update the routing layer and add Pydantic response schemas on top. Do not touch the database layer."
```

This creates a brand new agent (`flask-migration-v2`) starting from the exact state at the time of the snapshot, before the original agent did anything. The original agent (`flask-migration`) is still running and untouched.

You now have two agents working from the same checkpoint, with different instructions. You can connect to either:

```bash
mng connect flask-migration     # the original run
mng connect flask-migration-v2  # the more targeted retry
```

You can fork as many times as you want from the same snapshot.

***

## Why this is better than `git reset`

`git reset` gets your files back. It does not get back:

* Installed packages and virtual environments
* Tool caches (pip, npm, etc.)
* Environment variables and secrets that were set during provisioning
* tmux session history and shell state
* Any files the agent created outside the git working tree

A snapshot restores all of that. You're restoring the entire environment to a known-good state. It's also non-destructive. `git reset --hard` throws away a lot of code. Forking from a snapshot preserves every run so you can compare results or pull pieces from each.

***

## Step 5: Clean up when you're done

Snapshots consume storage, so delete them once you're confident in a result:

```bash
# Delete a specific snapshot
mng snapshot destroy flask-migration --snapshot $SNAP --force

# Or delete all snapshots for an agent
mng snapshot destroy flask-migration --all-snapshots --force
```

To preview what would be deleted without actually deleting it:

```bash
mng snapshot destroy flask-migration --all-snapshots --dry-run
```

Once the agent is done and its changes are merged, destroy the agents and their hosts to free up resources:

```bash
mng destroy flask-migration
mng destroy flask-migration-v2
```

***

## Full example, end to end

```bash
# 1. Launch agent on Modal
mng create flask-migration@.modal --no-connect \
  --message "Confirm you're ready."

# 2. Snapshot before the work starts
SNAP=$(mng snapshot create flask-migration --name before-migration --format "{snapshot_id}")

# 3. Send the task
mng message flask-migration "Migrate this Flask app to FastAPI..."

# 4. Agent goes off track — fork from the snapshot with better instructions
mng create flask-migration-v2@.modal --snapshot $SNAP \
  --message "Migrate this Flask app to FastAPI, but keep the database layer untouched..."

# 5. v2 looks good — pull its changes locally
mng pull flask-migration-v2

# 6. Clean up
mng snapshot destroy flask-migration --all-snapshots --force
mng destroy flask-migration
mng destroy flask-migration-v2
```
