File Edit Plugin

Safe file operations with diff preview, automatic backups, and undo capability. Shows unified diffs in permission prompts for clear visibility of changes.

Name file_edit
Type Tool Plugin (Registry-managed)
Tools Provided readFile, updateFile, writeNewFile, removeFile, moveFile, renameFile, undoFileChange, multiFileEdit, findAndReplace, restoreFile, listBackups
Total: 11 tools
User Commands None
Auto-approved readFile, undoFileChange, restoreFile, listBackups

Features

  • Diff Preview: Shows unified diff in permission prompts
  • Automatic Backups: Creates backups before any modification
  • Undo Support: Restore any file from its most recent backup
  • Safe Defaults: Only read-only operations are auto-approved: readFile, undoFileChange, restoreFile, listBackups
  • Gitignore Integration: Automatically adds .jaato to .gitignore
Basic usage
from jaato import PluginRegistry

registry = PluginRegistry()
registry.discover()

# Expose file_edit plugin
registry.expose_tool('file_edit')

# Or with custom backup directory
registry.expose_tool('file_edit', config={
    'backup_dir': '/custom/backup/path'
})
Model usage example
# Read a file (auto-approved)
readFile(path="src/main.py")

# Update existing file (shows diff)
updateFile(
    path="src/main.py",
    new_content="import sys\n\ndef main():\n..."
)

# Create new file (shows content)
writeNewFile(
    path="src/utils.py",
    content="def helper():\n    return 42"
)

# Move/rename a file (shows confirmation)
moveFile(
    source_path="src/old.py",
    destination_path="src/new.py"
)

# Undo last change (auto-approved)
undoFileChange(path="src/main.py")

Configuration Parameters

backup_dir

Directory where backups are stored. Backups are organized by original file path within this directory.

Typestr
Default.jaato/backups

Gitignore Integration

On initialization, the plugin automatically adds .jaato to your .gitignore if it exists and the entry is missing. This prevents backup files from being committed.

Backup Structure
Backups are stored with timestamps:

.jaato/backups/src/main.py/2024-01-15_14-30-00.bak

This allows multiple backups per file and easy manual recovery.
Backup directory structure
.jaato/
  backups/
    src/
      main.py/
        2024-01-15_14-30-00.bak
        2024-01-15_15-45-22.bak
      utils.py/
        2024-01-15_14-35-10.bak
    config/
      settings.json/
        2024-01-14_09-00-00.bak
Custom backup location
# Use a shared backup location
registry.expose_tool('file_edit', config={
    'backup_dir': '/var/backups/jaato'
})

# Or per-project location
registry.expose_tool('file_edit', config={
    'backup_dir': '.backups'
})

Tool Reference

readFile

Read the contents of a file. This is a safe, read-only operation and is auto-approved.

ParameterTypeDescription
pathstringPath to file

updateFile

Update an existing file with new content. Shows a unified diff for approval and creates a backup before modifying.

ParameterTypeDescription
pathstringPath to existing file
new_contentstringComplete new file content

writeNewFile

Create a new file. Fails if the file already exists (use updateFile instead).

ParameterTypeDescription
pathstringPath for new file
contentstringFile content to write

removeFile

Delete a file. Creates a backup before deletion so it can be restored.

ParameterTypeDescription
pathstringPath to file to delete

moveFile

Move or rename a file. Creates destination directories if needed. Creates a backup before moving. Fails if destination exists unless overwrite=True.

ParameterTypeDescription
source_pathstringPath to source file
destination_pathstringPath to move file to
overwritebooleanIf true, overwrite existing destination (default: false)

renameFile

Alias for moveFile. Use for renaming files (same parameters and behavior).

undoFileChange

Restore a file from its most recent backup. Auto-approved since it's a recovery operation.

ParameterTypeDescription
pathstringPath to file to restore

multiFileEdit

Execute multiple file operations atomically. Either ALL changes succeed or NONE are applied (automatic rollback on failure). Supports mixed operations: edit, create, delete, rename. Use this for refactoring operations that must succeed together (e.g., renaming a symbol across multiple files).

ParameterTypeDescription
operationsarrayArray of operations, each with an action field ("edit"/"create"/"delete"/"rename") plus action-specific fields (path, old, new, content, from, to, prologue, epilogue)

findAndReplace

Find and replace text across multiple files using regex patterns. Supports glob patterns for file selection and respects .gitignore by default. Use dry_run=true to preview changes without applying them.

ParameterTypeDescription
patternstringRegex pattern to search for
replacementstringReplacement string (supports backreferences like \1)
pathsstringGlob pattern for files to search (e.g., "src/**/*.py")
dry_runbooleanPreview changes without applying (default: false)
include_ignoredbooleanInclude .gitignore-excluded files (default: false)

restoreFile

Restore a file from a specific backup or the most recent backup. More targeted than undoFileChange: lets you choose which backup to restore from. Auto-approved since it's a recovery operation.

ParameterTypeDescription
pathstringPath to file to restore
backup_pathstringSpecific backup file to restore from (optional; uses latest if omitted)

listBackups

List all available file backups. Can filter by file path or list all backups in the session backup directory. Auto-approved since it is read-only.

ParameterTypeDescription
pathstringOptional file path to filter backups. If omitted, lists all backups.
readFile response
{
  "path": "src/main.py",
  "content": "import sys\n\ndef main():\n...",
  "size": 1234,
  "lines": 45
}
updateFile response
{
  "success": true,
  "path": "src/main.py",
  "size": 1456,
  "lines": 52,
  "backup": ".jaato/backups/src/main.py/2024-01-15_14-30-00.bak"
}
moveFile response
{
  "success": true,
  "source": "src/old.py",
  "destination": "src/new.py",
  "source_backup": ".jaato/backups/src/old.py/2024-01-15_14-30-00.bak"
}
undoFileChange response
{
  "success": true,
  "path": "src/main.py",
  "restored_from": ".jaato/backups/src/main.py/2024-01-15_14-30-00.bak",
  "message": "File restored from backup"
}

Permission Display

The file_edit plugin provides custom formatting for permission prompts, showing unified diffs for file modifications.

Update File Display

Shows a unified diff highlighting additions (green +) and deletions (red -).

New File Display

Shows all lines as additions since the file doesn't exist yet.

Delete File Display

Shows all lines as deletions, making it clear what will be removed.

Truncation

Large diffs are automatically truncated to prevent overwhelming the permission display. The summary indicates if truncation occurred.

Permission prompt example
Tool: updateFile
Summary: Update file: src/main.py (+5/-2 lines)

--- src/main.py (original)
+++ src/main.py (modified)
@@ -1,5 +1,8 @@
 import sys
+import os
+from pathlib import Path

 def main():
-    print("hello")
+    print("Hello, World!")
+    return 0

 if __name__ == "__main__":
     main()

[y]es / [n]o / [a]lways / [never]
New file prompt
Tool: writeNewFile
Summary: Create new file: src/utils.py (15 lines)

--- /dev/null
+++ src/utils.py
@@ -0,0 +1,15 @@
+"""Utility functions."""
+
+def helper():
+    """Return a helpful value."""
+    return 42
+
+def format_name(first, last):
+    """Format a full name."""
+    return f"{first} {last}"
...

[y]es / [n]o / [a]lways / [never]

Best Practices

Content Formatting

When using updateFile or writeNewFile, provide raw file content directly. Do not wrap in quotes or triple-quotes.

Use the Right Tool

  • updateFile: For existing files only
  • writeNewFile: For new files only
  • Using the wrong one returns a helpful error

Recovery Workflow

If a modification goes wrong:

  1. Use undoFileChange(path) to restore
  2. Review the original content with readFile(path)
  3. Make the correct modification
Correct content format
# CORRECT: Raw content
writeNewFile(
    path="example.py",
    content="import sys\n\ndef main():\n    pass"
)

# WRONG: Quoted content
writeNewFile(
    path="example.py",
    content='''"""
import sys

def main():
    pass
"""'''  # This writes the quotes too!
)
Error messages
// Using updateFile on non-existent file
{
  "error": "File not found: new.py. Use writeNewFile for new files."
}

// Using writeNewFile on existing file
{
  "error": "File already exists: main.py. Use updateFile to modify existing files."
}

// No backup available
{
  "error": "No backup found for: src/main.py"
}