# How Workspace Directory Management Serves Files Dynamically in Modly

> Modly dynamically serves 3D assets from WORKSPACE_DIR. Learn how path validation ensures security and enables runtime changes for efficient file management.

- Repository: [lightningpixel/modly](https://github.com/lightningpixel/modly)
- Tags: how-to-guide
- Published: 2026-08-15

---

**Modly serves generated 3D assets dynamically by resolving all `/workspace/` requests against a mutable `WORKSPACE_DIR` path that can be changed at runtime via environment variable or direct registry update, with security enforced through path validation that prevents directory traversal.**

In the [lightningpixel/modly](https://github.com/lightningpixel/modly) repository, the workspace directory acts as a live file system for meshes, textures, and intermediate processing results. The FastAPI backend implements a dynamic routing layer that reads the current workspace location on every request, enabling zero-downtime reconfiguration for multi-tenant deployments, temporary sandboxing, or shared storage scenarios.

## The GeneratorRegistry: Centralized Workspace Path Management

The foundation of dynamic file serving starts in [`services/generator_registry.py`](https://github.com/lightningpixel/modly/blob/main/services/generator_registry.py). At application startup, the **GeneratorRegistry** creates the workspace directory, prints its location for debugging, and exposes it globally:

```python

# From services/generator_registry.py

WORKSPACE_DIR: Path = Path.home() / ".modly" / "workspace"

```

The registry stores this path as a module-level variable that can be updated via `GeneratorRegistry.update_paths()`. This design choice makes the workspace location **mutable at runtime** rather than a frozen configuration constant.

## Dynamic File Serving via FastAPI Static Route

The actual file serving happens in [`api/main.py`](https://github.com/lightningpixel/modly/blob/main/api/main.py) through a FastAPI route that reads `WORKSPACE_DIR` fresh on every request:

```python

# api/main.py — dynamic workspace route (lines 58-66)

@app.get("/workspace/{full_path:path}")
async def serve_workspace_file(full_path: str):
    file_path = WORKSPACE_DIR / full_path
    if not file_path.exists():
        raise HTTPException(status_code=404, detail="File not found")
    return FileResponse(file_path)

```

Because `WORKSPACE_DIR` is resolved during request handling—not at import time—any change to the environment variable or a call to `update_paths()` immediately redirects subsequent requests. No server restart is required.

## Security: Path Validation Against Directory Traversal

Dynamic path resolution introduces security risks that Modly addresses in [`tools/modly-cli/agent.py`](https://github.com/lightningpixel/modly/blob/main/tools/modly-cli/agent.py). The **`_validate_workspace_path`** function enforces strict rules before any filesystem operation:

- Rejects absolute paths (starting with `/` or `\`)
- Blocks parent-directory references (`..`)
- Prevents Windows drive letter attacks

All workspace paths must remain relative to the configured root. This validation is applied consistently across CLI tools and API interactions.

## Relative Path Helpers for CLI Integration

The CLI layer in [`agent.py`](https://github.com/lightningpixel/modly/blob/main/agent.py) provides two key utilities for safe workspace interaction:

| Function | Purpose |
|----------|---------|
| **`_workspace_relative_path`** | Extracts path after `/workspace/` prefix and validates it |
| **`_export_workspace_path`** | Builds download URLs with validated path parameters |

These helpers bridge local file operations with server-side workspace serving, ensuring the same security constraints apply whether files are accessed via HTTP or processed through the command-line interface.

## Router-Level Path Resolution

Other API routers implement similar dynamic resolution patterns. In [`api/routers/optimize.py`](https://github.com/lightningpixel/modly/blob/main/api/routers/optimize.py), the **`_resolve_input_path`** function demonstrates the standard approach:

```python

# From api/routers/optimize.py (lines 49-62)

def _resolve_input_path(path: str) -> Path:
    if Path(path).is_absolute():
        return Path(path)  # Absolute paths used as-is

    resolved = WORKSPACE_DIR / path
    # Verify resolved path stays within workspace

    if not str(resolved.resolve()).startswith(str(WORKSPACE_DIR.resolve())):
        raise ValueError("Path escapes workspace directory")
    return resolved

```

This pattern guarantees that mesh operations always target the current workspace location, even when the directory changes mid-session.

## Changing the Workspace Directory at Runtime

The dynamic design enables flexible deployment scenarios. To relocate the workspace without restarting:

```python
import os
from pathlib import Path
from services.generator_registry import generator_registry

# Method 1: Environment variable

os.environ["WORKSPACE_DIR"] = "/mnt/shared_workspace"

# Method 2: Direct registry update

generator_registry.update_paths(workspace_dir=Path("/mnt/shared_workspace"))

# Subsequent GET /workspace/... calls serve from new location

```

Both methods update the same underlying `WORKSPACE_DIR` reference, ensuring consistency across all components.

## Retrieving Files from the Workspace

Clients access generated assets through simple HTTP requests:

```python

# Download a generated mesh from current workspace

import requests

url = "http://localhost:8765/workspace/Default/robot.glb"
resp = requests.get(url)
resp.raise_for_status()

with open("robot.glb", "wb") as f:
    f.write(resp.content)

```

Or via command line:

```bash
curl -O http://localhost:8765/workspace/Default/robot.glb

```

The server automatically serves from whichever directory is currently configured as `WORKSPACE_DIR`, regardless of when the file was originally generated.

## Summary

- **[`services/generator_registry.py`](https://github.com/lightningpixel/modly/blob/main/services/generator_registry.py)** exposes `WORKSPACE_DIR` as a mutable global path, created at startup with default `~/.modly/workspace`

- **[`api/main.py`](https://github.com/lightningpixel/modly/blob/main/api/main.py)** serves files through `/workspace/{path}` by reading `WORKSPACE_DIR` on each request, enabling instant reconfiguration

- **[`agent.py`](https://github.com/lightningpixel/modly/blob/main/agent.py)** implements **`_validate_workspace_path`** to block directory traversal and drive-letter attacks

- **Relative-path helpers** (`_workspace_relative_path`, `_export_workspace_path`) ensure CLI and API interactions follow identical security rules

- **Router functions** like **`_resolve_input_path`** in [`optimize.py`](https://github.com/lightningpixel/modly/blob/main/optimize.py) extend dynamic resolution to all mesh processing operations

## Frequently Asked Questions

### How do I change the Modly workspace directory without restarting the server?

Update the `WORKSPACE_DIR` environment variable and call `generator_registry.update_paths()` with the new `Path`. The FastAPI route reads this value fresh on every request, so subsequent `/workspace/` calls immediately serve from the new location.

### What prevents users from accessing files outside the workspace?

The **`_validate_workspace_path`** function in [`agent.py`](https://github.com/lightningpixel/modly/blob/main/agent.py) rejects absolute paths, parent-directory references (`..`), and Windows drive letters. All paths must be relative and resolve to a location inside `WORKSPACE_DIR`.

### Where is the default workspace directory created?

[`services/generator_registry.py`](https://github.com/lightningpixel/modly/blob/main/services/generator_registry.py) creates `~/.modly/workspace` at startup if it doesn't exist, printing the absolute path for verification. This default can be overridden through the `WORKSPACE_DIR` environment variable before launch.

### Can external tools download workspace files directly?

Yes. Any HTTP client can fetch files via `GET /workspace/{relative_path}`. The CLI's **`_export_workspace_path`** helper constructs these URLs with proper URL-encoding and validation for safe direct downloads.