# ChatDev Workflow Versioning and Storage Management: A Complete Technical Guide

> Master ChatDev workflow versioning and storage management with this technical guide. Learn how ChatDev uses semantic versioning and secure file storage for definitions and outputs.

- Repository: [OpenBMB/ChatDev](https://github.com/OpenBMB/ChatDev)
- Tags: how-to-guide
- Published: 2026-04-01

---

**ChatDev manages workflow versioning through a semantic version field in YAML design documents and stores both definitions and execution outputs in a secure, validated file-system hierarchy separated into YAML directories and per-session warehouses.**

ChatDev, the multi-agent collaborative development framework by OpenBMB, treats every workflow as a version-aware YAML design document with strict storage governance. Understanding ChatDev workflow versioning and storage management is essential for maintaining reproducible AI-driven software engineering pipelines and securing multi-tenant deployments against path-traversal attacks.

## How ChatDev Implements Workflow Versioning

ChatDev embeds versioning metadata directly into workflow definitions through the `DesignConfig` class in [`entity/configs/graph.py`](https://github.com/OpenBMB/ChatDev/blob/main/entity/configs/graph.py). This approach ensures that every workflow carries its own compatibility identifier without requiring external metadata databases.

### The version Field in Design Documents

Every workflow YAML must contain a top-level **`version`** key that follows semantic versioning conventions. When `check.check.load_config` parses the file, it instantiates a `DesignConfig` object that exposes this value:

```python

# Simplified from check/check.py → load_config

design = load_config(yaml_path)          # returns a DesignConfig instance

print(design.version)                    # e.g. "1.2.3"

```

The version string enables downstream CI pipelines and audit systems to enforce migration rules or compatibility checks before executing potentially breaking graph changes.

### Default Version Handling

If the YAML omits the version key, `DesignConfig.from_dict` automatically injects `"0.0.0"` as the default value. This fallback is defined in [`entity/configs/graph.py`](https://github.com/OpenBMB/ChatDev/blob/main/entity/configs/graph.py) (lines 273–284) and guarantees that no workflow object exists in an undefined state, allowing version comparison logic to proceed safely even on legacy files.

## Secure Workflow Storage Architecture

The storage layer isolates workflow manipulation logic inside [`server/services/workflow_storage.py`](https://github.com/OpenBMB/ChatDev/blob/main/server/services/workflow_storage.py), providing a testable interface for filename validation, persistence, and renaming operations.

### Filename Validation and Sanitization

Before any write operation, `validate_workflow_filename` enforces a strict whitelist pattern (`^[a-zA-Z0-9._-]+$`) that rejects path-traversal sequences (`..`, leading `/`) and mandates `.yaml` or `.yml` extensions. This validation runs consistently across `persist_workflow`, `rename_workflow`, and `copy_workflow` to prevent directory escape vulnerabilities in multi-tenant environments.

### Persisting, Renaming, and Copying Workflows

The `persist_workflow` function (lines 37–66) writes raw YAML content to `YAML_DIR / safe_filename`, wrapping I/O failures in `WorkflowExecutionError` with structured logging. When renaming workflows via `rename_workflow` (lines 111–165), ChatDev automatically rewrites the internal `id:` field inside the YAML to match the new file stem through `_update_workflow_id`, preventing identifier drift. Both rename and copy operations guard against name collisions by raising `ResourceConflictError` if the target filename already exists.

## Runtime Output and Warehouse Management

After execution, ChatDev archives artefacts in a dedicated *warehouse* directory structure defined by `WARE_HOUSE_DIR` in [`server/settings.py`](https://github.com/OpenBMB/ChatDev/blob/main/server/settings.py). This separation of design documents from runtime outputs enables clean backup strategies and analytics aggregation.

### ResultArchiver and Execution Artefacts

The `ResultArchiver.export` method in [`workflow/runtime/result_archiver.py`](https://github.com/OpenBMB/ChatDev/blob/main/workflow/runtime/result_archiver.py) (lines 21–33) persists three key files after each run:

- **`token_usage_<graph>.json`**: Contains counters from the `TokenTracker` instance
- **[`execution_logs.json`](https://github.com/OpenBMB/ChatDev/blob/main/execution_logs.json)**: Structured logs captured by the `LogManager`
- **Final result artefacts**: Returned via WebSocket and simultaneously written to the same directory by the executor

### Directory Structure and Session Isolation

The base output path is constructed by combining `WARE_HOUSE_DIR` with a unique session identifier (e.g., `WareHouse/session_12345`). The `GraphConfig` class in [`entity/graph_config.py`](https://github.com/OpenBMB/ChatDev/blob/main/entity/graph_config.py) (lines 14–18) carries this `output_root` through the execution lifecycle, ensuring that concurrent workflow runs cannot overwrite each other's data. This deterministic layout supports batch-mode analytics and forensic debugging across multiple ChatDev sessions.

## Practical Implementation Examples

### Defining a Versioned Workflow

Create a YAML file with an explicit version string that `DesignConfig` will parse:

```yaml

# my_workflow.yaml

version: "1.3.0"
id: my_workflow
vars:
  API_KEY: "${API_KEY}"
graph:
  nodes:
    - name: fetch_data
      type: python
      config:
        command: |
          import requests
          data = requests.get("https://api.example.com").json()
  edges:
    - source: fetch_data
      target: process_data

```

### Exporting a Template with CLI Version Pinning

Use the export tool in [`tools/export_design_template.py`](https://github.com/OpenBMB/ChatDev/blob/main/tools/export_design_template.py) to generate a template with a specific version:

```bash
python -m chatdev.tools.export_design_template \
    --output template.yaml \
    --version "2.0.0"

```

This creates a YAML document with `version: "2.0.0"` at the top level (see lines 37–40 in the source).

### Persisting Workflows via the Python API

Programmatically store a workflow with full validation:

```python
from pathlib import Path
from server.services.workflow_storage import validate_workflow_filename, persist_workflow

yaml_content = Path("my_workflow.yaml").read_text()
safe_name, yaml_obj = validate_workflow_filename("my_workflow.yaml", yaml_content)
persist_workflow(
    safe_filename=safe_name,
    content=yaml_content,
    yaml_content=yaml_obj,
    action="create",
    directory=Path("yaml_instance")   # Corresponds to YAML_DIR from settings

)

```

### Renaming a Workflow with Automatic ID Updates

Rename a file while keeping the internal identifier synchronized:

```python
from server.services.workflow_storage import rename_workflow

rename_workflow(
    source_filename="my_workflow.yaml",
    target_filename="my_new_workflow.yaml",
    directory=Path("yaml_instance")
)

```

Behind the scenes, this updates the `id:` field to `my_new_workflow` (see lines 111–165 in [`workflow_storage.py`](https://github.com/OpenBMB/ChatDev/blob/main/workflow_storage.py)).

### Accessing Archived Execution Results

Retrieve token usage and logs from a completed session:

```python
from pathlib import Path
import json

output_dir = Path("WareHouse") / "session_12345"

with (output_dir / "token_usage_my_workflow.json").open() as f:
    token_usage = json.load(f)

with (output_dir / "execution_logs.json").open() as f:
    logs = json.load(f)

print("Tokens used:", token_usage)
print("Log entries:", len(logs))

```

These files are written by `ResultArchiver.export` as implemented in [`workflow/runtime/result_archiver.py`](https://github.com/OpenBMB/ChatDev/blob/main/workflow/runtime/result_archiver.py).

## Summary

- **Versioning is embedded** in every workflow YAML via the `version` field managed by `DesignConfig` in [`entity/configs/graph.py`](https://github.com/OpenBMB/ChatDev/blob/main/entity/configs/graph.py), defaulting to `"0.0.0"` when omitted.
- **Storage security** relies on [`server/services/workflow_storage.py`](https://github.com/OpenBMB/ChatDev/blob/main/server/services/workflow_storage.py) functions that validate filenames against whitelist patterns and prevent path-traversal attacks.
- **Lifecycle operations** like `rename_workflow` automatically synchronize the internal YAML `id:` field with the filesystem name to prevent reference drift.
- **Execution isolation** is enforced through per-session warehouse directories configured in [`server/settings.py`](https://github.com/OpenBMB/ChatDev/blob/main/server/settings.py) and managed by `ResultArchiver` in [`workflow/runtime/result_archiver.py`](https://github.com/OpenBMB/ChatDev/blob/main/workflow/runtime/result_archiver.py).
- **Auditability** is supported by deterministic output paths that separate design documents (`YAML_DIR`) from runtime artefacts (`WARE_HOUSE_DIR`).

## Frequently Asked Questions

### What happens if I omit the version field in my ChatDev workflow YAML?

If the `version` key is missing, `DesignConfig.from_dict` in [`entity/configs/graph.py`](https://github.com/OpenBMB/ChatDev/blob/main/entity/configs/graph.py) automatically assigns the default value `"0.0.0"`. This ensures that all workflow objects carry a comparable version identifier, preventing null-reference errors in downstream compatibility checks.

### How does ChatDev prevent directory traversal attacks when saving workflows?

The `validate_workflow_filename` function in [`server/services/workflow_storage.py`](https://github.com/OpenBMB/ChatDev/blob/main/server/services/workflow_storage.py) enforces a strict regex whitelist (`^[a-zA-Z0-9._-]+$`) that rejects path separators, parent-directory references (`..`), and absolute paths. Only files ending in `.yaml` or `.yml` are accepted, ensuring all writes remain confined to the designated `YAML_DIR`.

### Where does ChatDev store execution logs and token usage after a workflow completes?

According to [`workflow/runtime/result_archiver.py`](https://github.com/OpenBMB/ChatDev/blob/main/workflow/runtime/result_archiver.py), the `ResultArchiver.export` method writes `token_usage_<graph>.json` and [`execution_logs.json`](https://github.com/OpenBMB/ChatDev/blob/main/execution_logs.json) into a session-specific subdirectory under `WARE_HOUSE_DIR` (defined in [`server/settings.py`](https://github.com/OpenBMB/ChatDev/blob/main/server/settings.py)). The exact path follows the pattern `<output_root>/<graph_name>/`, where `output_root` is injected via `GraphConfig`.

### Can I rename a workflow file without breaking internal references?

Yes. The `rename_workflow` function in [`server/services/workflow_storage.py`](https://github.com/OpenBMB/ChatDev/blob/main/server/services/workflow_storage.py) (lines 111–165) handles this atomically: it validates the new filename, checks for collisions, moves the file, and calls `_update_workflow_id` to rewrite the YAML's internal `id:` field to match the new file stem, maintaining consistency between the filesystem and the workflow definition.