# How to Rollback to a Previous Version in Distilly: Complete CLI and Python Guide

> Easily rollback to a previous Distilly version using the CLI or Python. Learn to restore skill states safely with automatic backups.

- Repository: [Tianyi Zhou/distilly](https://github.com/titanwings/distilly)
- Tags: how-to-guide
- Published: 2026-09-10

---

**Distilly stores every skill's artifacts in a hidden `versions/` folder and provides the [`tools/version_manager.py`](https://github.com/titanwings/distilly/blob/main/tools/version_manager.py) CLI to restore previous states while automatically backing up your current version before overwriting.**

Distilly is an open-source framework for generating and managing AI skills. When you need to revert changes, the built-in **Skill Version Manager** enables you to rollback to a previous version in Distilly by manipulating versioned archives stored within each skill directory.

## Understanding Distilly's Version Archive Structure

Every generated skill maintains a **versioned archive** inside a hidden `versions/` folder located within the skill directory. According to the source code in [`tools/version_manager.py`](https://github.com/titanwings/distilly/blob/main/tools/version_manager.py), this archive preserves the four primary artifacts defined in [`tools/skill_schema.py`](https://github.com/titanwings/distilly/blob/main/tools/skill_schema.py): **SKILL.md**, **work.md**, **persona.md**, and **manifest.json**.

The `PRIMARY_ARTIFACTS` constant (lines 25-33 of [`skill_schema.py`](https://github.com/titanwings/distilly/blob/main/skill_schema.py)) defines which files the version manager considers essential. When you archive or rollback, the system only interacts with these specific files, ensuring consistency across skill versions.

## How the Rollback Mechanism Works

The rollback process in [`tools/version_manager.py`](https://github.com/titanwings/distilly/blob/main/tools/version_manager.py) follows a strict five-step safety protocol:

1. **Locate the skill directory** using the supplied slug and character preset.
2. **Resolve the target version** via `resolve_contained_child()` (line 86), which validates that the requested version exists inside `skill_dir/versions/<target_version>`.
3. **Create a backup of current artifacts** in a new sub-directory named `<current_version>_before_rollback` (lines 103-108). This guarantees you can restore the pre-rollback state if needed.
4. **Copy each artifact** listed in `PRIMARY_ARTIFACTS` from the archived version into the live skill directory (lines 115-119).
5. **Update metadata** in [`meta.json`](https://github.com/titanwings/distilly/blob/main/meta.json) to record the rollback: it stamps a new lifecycle version (`<target_version>_restored`), saves the original version in `rollback_from`, and refreshes `updated_at` (lines 121-124).

## CLI Workflow for Rolling Back

The version manager exposes a pure-Python CLI interface. Below are the complete commands for managing versions.

### List Archived Versions

Before rolling back, identify available versions using the `list` action, which invokes `list_versions()` (lines 41-69):

```bash
python -m tools.version_manager \
    --action list \
    --slug my-skill \
    --character colleague

```

This outputs every stored version with timestamps and artifact names, allowing you to identify the correct target version string (e.g., `v1`, `v2`).

### Create an Optional Backup

To force a snapshot of the live artifacts before any change, use the `backup` action, which calls `backup_current_version()` (lines 33-57):

```bash
python -m tools.version_manager \
    --action backup \
    --slug my-skill \
    --character colleague

```

### Execute the Rollback

Perform the restoration using the `rollback` action. This triggers the core `rollback()` function and updates your [`meta.json`](https://github.com/titanwings/distilly/blob/main/meta.json) automatically:

```bash
python -m tools.version_manager \
    --action rollback \
    --slug my-skill \
    --version v1 \
    --character colleague

```

Upon success, the console prints: `rolled back to v1: SKILL.md, work.md, persona.md, manifest.json`.

### Clean Up Old Versions

To prune archives older than `MAX_VERSIONS` (default 10) and keep storage tidy, run the `cleanup` action, which invokes `cleanup_old_versions()` (lines 60-79):

```bash
python -m tools.version_manager \
    --action cleanup \
    --slug my-skill \
    --character colleague

```

This removes excess archives and prints each deletion to stdout.

## Programmatic Rollback in Python

Because the version manager is implemented as a Python module, you can import its functions directly into automation scripts without shelling out to the CLI:

```python
from pathlib import Path
from tools.version_manager import (
    resolve_base_dir,
    rollback,
)

# Resolve the skill location using character preset

skill_root = resolve_base_dir(base_dir_arg=None, character="colleague")
skill_dir = skill_root / "my-skill"

target_version = "v1"

if rollback(skill_dir, target_version):
    print(f"Successfully rolled back {skill_dir.name} to {target_version}")
else:
    print("Rollback failed – check the output above for errors")

```

This approach is useful for CI/CD pipelines or custom skill management dashboards.

## Safety Features and Path Validation

The rollback process is secure because all path handling routes through `validate_path_segment()` and `resolve_contained_child()` (lines 34-68 of [`skill_schema.py`](https://github.com/titanwings/distilly/blob/main/skill_schema.py)). These functions prevent directory-traversal attacks and symlink-escape vulnerabilities by validating every path segment before file operations occur.

Additionally, the automatic creation of the `<current_version>_before_rollback` backup ensures that even if the rollback itself fails or you change your mind, the pre-rollback state remains recoverable.

## Summary

- Distilly stores skill artifacts in a hidden `versions/` folder inside each skill directory.
- The **Skill Version Manager** in [`tools/version_manager.py`](https://github.com/titanwings/distilly/blob/main/tools/version_manager.py) handles all versioning operations.
- Rollbacks automatically create a safety backup named `<current_version>_before_rollback` before overwriting files.
- Only files defined in `PRIMARY_ARTIFACTS` (**SKILL.md**, **work.md**, **persona.md**, **manifest.json**) are archived and restored.
- Path validation via `validate_path_segment()` and `resolve_contained_child()` ensures security against directory traversal.

## Frequently Asked Questions

### Where does Distilly store previous versions?

Distilly stores previous versions in a hidden `versions/` sub-directory inside the skill's folder. Each archived version resides in its own folder (e.g., `skill_dir/versions/v1/`) and contains copies of the four primary artifacts defined in [`tools/skill_schema.py`](https://github.com/titanwings/distilly/blob/main/tools/skill_schema.py).

### Will I lose my current work when rolling back?

No. Distilly automatically creates a backup of your current version in a folder named `<current_version>_before_rollback` before copying archived files into the live directory. This safety copy preserves your pre-rollback state indefinitely alongside other archived versions.

### Can I rollback without using the command line?

Yes. You can import `rollback()` and `resolve_base_dir()` directly from `tools.version_manager` in your Python scripts. This programmatic approach allows you to trigger rollbacks from within applications, automation scripts, or Jupyter notebooks without invoking the CLI.

### How many versions does Distilly retain by default?

The version manager retains a maximum of 10 versions by default, controlled by the `MAX_VERSIONS` constant. You can remove older archives manually using the `--action cleanup` command, which prunes everything beyond the most recent 10 versions.