file-tracker
Log all file changes (write, edit, delete) to a SQLite database for debugging and audit. Use when: (1) Tracking code changes, (2) Debugging issues, (3) Auditing file modifications, or (4) The user asks to track file changes.
git clone --depth 1 https://github.com/besoeasy/open-skills /tmp/file-tracker && cp -r /tmp/file-tracker/skills/file-tracker ~/.claude/skills/file-trackerSKILL.md
# File Tracker
Log every file change (write, edit, delete) to a SQLite database for debugging, audit trails, and version history tracking. Works with any file operation system or code editor.
## When to use
- Tracking file modifications during development
- Creating audit trails for file changes
- Debugging what files were modified and when
- Building version history without git
- User asks to track or review file changes
## Required tools / APIs
- Python standard library (sqlite3, datetime, os)
- Any programming language with SQLite support
No external APIs or services required.
## Database Schema
```sql
CREATE TABLE IF NOT EXISTS file_changes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT NOT NULL,
action TEXT NOT NULL, -- 'write', 'edit', 'delete', 'rename'
file_path TEXT NOT NULL,
old_content TEXT, -- for edits/deletes
new_content TEXT, -- for writes/edits
file_size INTEGER, -- size in bytes
metadata TEXT, -- JSON: user, session_id, etc.
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_file_path ON file_changes(file_path);
CREATE INDEX idx_timestamp ON file_changes(timestamp);
CREATE INDEX idx_action ON file_changes(action);
-- Automatic purge: delete records older than 1 year
DELETE FROM file_changes WHERE created_at < datetime('now', '-1 year');
```
**Fields:**
- `id` - Auto-incrementing primary key
- `timestamp` - ISO 8601 timestamp of the change
- `action` - Type of operation: 'write', 'edit', 'delete', 'rename'
- `file_path` - Absolute or relative path to the file
- `old_content` - Previous content (for edits) or deleted content (for deletes)
- `new_content` - New content (for writes/edits)
- `file_size` - File size in bytes after operation
- `metadata` - JSON field for additional context (user, session, tools)
- `created_at` - Database insertion timestamp
## Basic Implementation
### Python
**Initialize database:**
```python
import sqlite3
from datetime import datetime
from pathlib import Path
import json
import os
# Configure database path (customize as needed)
DB_PATH = Path.home() / ".file_tracker" / "changes.db"
def init_db():
"""Initialize database and create tables."""
DB_PATH.parent.mkdir(parents=True, exist_ok=True)
conn = sqlite3.connect(str(DB_PATH))
conn.execute("""
CREATE TABLE IF NOT EXISTS file_changes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT NOT NULL,
action TEXT NOT NULL,
file_path TEXT NOT NULL,
old_content TEXT,
new_content TEXT,
file_size INTEGER,
metadata TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
""")
conn.execute("CREATE INDEX IF NOT EXISTS idx_file_path ON file_changes(file_path)")
conn.execute("CREATE INDEX IF NOT EXISTS idx_timestamp ON file_changes(timestamp)")
conn.execute("CREATE INDEX IF NOT EXISTS idx_action ON file_changes(action)")
conn.commit()
conn.close()
def purge_old_changes():
"""Delete file change records older than 1 year to keep the database size sane."""
conn = sqlite3.connect(str(DB_PATH))
conn.execute("DELETE FROM file_changes WHERE created_at < datetime('now', '-1 year')")
conn.commit()
conn.close()
# Initialize on import and purge old records
init_db()
purge_old_changes()
```
**Log file changes:**
```python
def log_file_change(
action: str,
file_path: str,
old_content: str = None,
new_content: str = None,
metadata: dict = None
):
"""Log a file change to the database."""
conn = sqlite3.connect(str(DB_PATH))
try:
# Get file size if file exists
file_size = None
if os.path.exists(file_path) and action != "delete":
file_size = os.path.getsize(file_path)
conn.execute(
"""INSERT INTO file_changes
(timestamp, action, file_path, old_content, new_content, file_size, metadata)
VALUES (?, ?, ?, ?, ?, ?, ?)""",
(
datetime.utcnow().isoformat(),
action,
file_path,
old_content[:5000] if old_content else None, # Truncate large content
new_content[:5000] if new_content else None,
file_size,
json.dumps(metadata) if metadata else None
)
)
conn.commit()
finally:
conn.close()
# Usage examples
log_file_change("write", "/path/to/file.py", new_content="print('Hello')")
log_file_change("edit", "/path/to/file.py", old_content="print('Hello')", new_content="print('Hi')")
log_file_change("delete", "/path/to/file.py", old_content="print('Hi')")
log_file_change("write", "/path/to/config.json", new_content='{"key": "value"}',
metadata={"user": "john", "session": "sess_123"})
```
**Tracked file operations:**
```python
def tracked_write(file_path: str, content: str, metadata: dict = None):
"""Write file and log the change."""
with open(file_path, 'w') as f:
f.write(content)
log_file_change("write", file_path, new_content=content, metadata=metadata)
def tracked_edit(file_path: str, old_content: str, new_content: str, metadata: dict = None):
"""Edit file and log the change."""
with open(file_path, 'w') as f:
f.write(new_content)
log_file_change("edit", file_path, old_content=old_content,
new_content=new_content, metadata=metadata)
def tracked_delete(file_path: str, metadata: dict = None):
"""Delete file and log the change."""
with open(file_path, 'r') as f:
old_content = f.read()
os.remove(file_path)
log_file_change("delete", file_path, old_content=old_content, metadata=metadata)
# Usage
tracked_write("example.txt", "Hello, World!")
tracked_edit("example.txt", "Hello, World!", "Hello, Python!")
tracked_delete("example.txt")
```
**QueryEncrypt and decrypt files or streams using age — a simple, modern, and secure encryption tool with small explicit keys, passphrase support, SSH key support, post-quantum hybrid keys, and UNIX-style composability. No config options, no footguns.
Upload and host files anonymously using decentralized storage with Originless and IPFS.
Automate web browsers for AI agents using agent-browser CLI with deterministic element selection.
Star all repositories from a GitHub user automatically. Use when: (1) Supporting open source creators, (2) Bulk discovery of useful projects, or (3) Automating GitHub engagement.
Automatically creates user-facing changelogs from git commits by analyzing commit history, categorizing changes, and transforming technical commits into clear, customer-friendly release notes. Turns hours of manual changelog writing into minutes of automated generation.
Log all chat messages to a SQLite database for searchable history and audit. Use when: (1) Building chat history, (2) Auditing conversations, (3) Searching past messages, or (4) User asks to log chats.
Check cryptocurrency wallet balances across multiple blockchains using free public APIs.
Calculate line-of-sight and road distances between two cities using free OpenStreetMap services.