Skip to content
archived Visibility internal Owner erik@uvilo.com Approver _ Created _ Updated _

Uvilo OS Plan Trash MCP

Purpose

Provide safe “delete” operations for the assistant by moving items to a trash directory instead of permanently deleting them, with the ability to restore.

Trash Location

/workspace/erik/uvilo-os/.trash/ (already exists, already gitignored)

Key Design: Path Hierarchy Preservation

When trashing a file, recreate its relative path from the repo root inside .trash/.

Example:

  • Trashing /workspace/erik/uvilo-os/Architecture/Old_Doc.md
  • Moves to: /workspace/erik/uvilo-os/.trash/Architecture/Old_Doc__2026-03-14T18-30-00.md

This means:

  • You always know where a trashed item came from (its restore path)
  • No filename collisions — every trash operation produces a unique name
  • Restore is straightforward — strip the timestamp suffix and reverse the move

Timestamp in Filename

Every trashed item gets a timestamp suffix appended to its name:

<original_name>__<ISO-timestamp>.<ext>

Examples:

  • Old_Doc.mdOld_Doc__2026-03-14T18-30-00.md
  • Scripts/Scripts__2026-03-14T18-30-00/
  • Makefile (no ext) → Makefile__2026-03-14T18-30-00

Format: __YYYY-MM-DDTHH-MM-SS (double underscore delimiter, hyphens instead of colons for filesystem safety)

Benefits:

  • Trash date is visible at a glance — no manifest or metadata file needed
  • Collision handling comes for free
  • Age-based empty_trash(older_than_days=N) is trivial — parse the filename
  • No external state to keep in sync

Tradeoff:

  • Untrash must strip the timestamp suffix to restore the original name

Tools (6)

1. trash_file(path: str) → str

  • Validates path is within the repo and is a file
  • Validates it’s not inside .trash/, .git/, or other protected paths
  • Computes relative path from repo root
  • Appends timestamp suffix to filename (before extension)
  • Creates parent directories in .trash/ as needed
  • Moves file to .trash/<relative_path_with_timestamp>
  • Returns confirmation with original and trash paths

2. trash_directory(path: str) → str

  • Same as trash_file but for directories
  • Appends timestamp suffix to the directory name
  • Moves the entire directory tree
  • Validates it’s not a protected path (.trash/, .git/, .internal/)
  • Returns confirmation with item count

3. untrash_file(trash_path: str) → str

  • Takes a path within .trash/
  • Strips the timestamp suffix to derive the original filename
  • Derives the original location from the relative path
  • Validates the original location doesn’t already have a file (error if so)
  • Moves file back to original location
  • Cleans up empty parent dirs in .trash/
  • Returns confirmation

4. untrash_directory(trash_path: str) → str

  • Same as untrash_file but for directories
  • Strips timestamp suffix from directory name
  • Validates target doesn’t already exist
  • Moves directory back, cleans up empty parents in .trash/

5. list_trash(path: str = "") → str

  • Lists contents of .trash/, optionally filtered to a subdirectory
  • Shows each item with its original name, trash date (parsed from suffix), and size
  • Useful before calling untrash or empty_trash

6. empty_trash(older_than_days: int = 30) → str

  • Permanently deletes items trashed more than N days ago (default: 30 days) (parsed from the timestamp suffix in each filename)
  • Pass older_than_days=0 to delete ALL items regardless of age
  • Returns summary: number of items deleted, space freed
  • Irreversible — the assistant should confirm with the user before calling

Implementation Details

  • Language: Python (matches uvilo-git-push.py pattern)
  • Framework: FastMCP (from mcp package, same as git-push server)
  • Transport: stdio
  • File location: /workspace/uvilo-trash.py (alongside uvilo-git-push.py)
  • Repo root constant: /workspace/erik/uvilo-os
  • Trash root constant: /workspace/erik/uvilo-os/.trash
  • Protected paths: Refuse to trash .git/, .trash/, .internal/node_modules/, .internal/dist/, .internal/.astro/
  • No shell dependency — uses Python’s shutil.move, shutil.rmtree, os.makedirs, pathlib, etc.
  • Timestamp parsing regex: __(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}) to extract the trash date from any filename

LibreChat Config Addition

uvilo-trash:
  title: "Uvilo OS Trash"
  description: "Safe delete operations — moves files to .trash/ instead of permanent deletion"
  command: uvx
  args:
    - --with
    - mcp
    - python3
    - /workspace/uvilo-trash.py
  timeout: 30000
  serverInstructions: |
    Safe file/directory deletion for the Uvilo OS repository.
    Items are moved to .trash/ (gitignored) preserving their original path hierarchy.
    Trashed items have a timestamp suffix showing when they were trashed.
    Use trash_file/trash_directory instead of permanent deletion.
    Use list_trash to see what's in the trash.
    Use untrash_file/untrash_directory to restore items to their original location.
    Use empty_trash to permanently delete trashed items (ask user first — irreversible).
    Default retention: 30 days. Items older than 30 days are purged by default.

Migration

Empty the current .trash/ directory (3 stale flat files with no hierarchy or timestamps). Just delete them during implementation — they’re throwaway.