Every developer’s download folder eventually devolves into a multi-gigabyte graveyard of installer executables, temporary zip archives, random screenshots, and duplicate PDFs. While graphical disk cleanup utilities exist, they are often bloated, ad-supported, or require manual clicks.
To solve this once and for all, I built cleanbot—a lightweight, zero-dependency background maintenance tool written in pure Node.js that runs autonomously on a daily schedule.
The Design Philosophy: Zero Dependencies
Many command-line utilities quickly pull in dozens of npm packages (glob, fs-extra, winston, axios) for simple tasks. For a background scheduler that runs silently in the background, minimizing attack surface and memory footprint is paramount.
cleanbot was built using strictly Node.js standard libraries:
fs/promisesfor asynchronous filesystem operations.pathfor cross-platform directory resolution.- Native
fetchfor dispatching Discord webhook telemetry notifications.
1. Extension-Based Auto Sorting
The first responsibility of the daemon is classifying scattered files in Downloads/ into dedicated categorization buckets (Images/, Videos/, Documents/, Archives/, Executables/):
const sortRules = {
Images: ['.png', '.jpg', '.jpeg', '.webp', '.gif', '.svg'],
Videos: ['.mp4', '.mkv', '.mov', '.avi'],
Documents: ['.pdf', '.docx', '.xlsx', '.pptx', '.txt'],
Archives: ['.zip', '.rar', '.7z', '.tar', '.gz'],
Executables: ['.exe', '.msi', '.apk'],
};
export async function sortDownloads(downloadsDir, rules) {
const entries = await fs.readdir(downloadsDir, { withFileTypes: true });
for (const entry of entries) {
if (entry.isDirectory()) continue;
const ext = path.extname(entry.name).toLowerCase();
for (const [folder, extensions] of Object.entries(rules)) {
if (extensions.includes(ext)) {
const destDir = path.join(downloadsDir, folder);
await fs.mkdir(destDir, { recursive: true });
await fs.rename(
path.join(downloadsDir, entry.name),
path.join(destDir, entry.name)
);
break;
}
}
}
} 2. Age-Based File Expiration & Safe Temp Purging
Temporary files and downloads older than 30 days are automatically deleted to reclaim disk space. Crucially, active lock contention is caught gracefully without terminating the process:
export async function cleanOldFiles(targetDir, maxAgeDays = 30) {
const cutoffTime = Date.now() - maxAgeDays * 24 * 60 * 60 * 1000;
const entries = await fs.readdir(targetDir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(targetDir, entry.name);
try {
const stats = await fs.stat(fullPath);
if (stats.isFile() && stats.mtimeMs < cutoffTime) {
await fs.unlink(fullPath);
}
} catch {
// Gracefully bypass locked system files or permissions
}
}
} 3. Discord Telemetry via Webhook
When the daily cleanup completes, cleanbot compiles a summary log and posts a formatted notification to a private Discord channel using Discord’s Webhook API.
await fetch(process.env.DISCORD_WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
embeds: [
{
title: '🧹 Daily File Maintenance Completed',
description: `Cleaned temp directories and sorted downloads successfully.`,
color: 0xe0533c,
timestamp: new Date().toISOString(),
},
],
}),
}); Scheduling the Task
Whether running on Windows via Task Scheduler (schtasks) or on Linux via a systemd timer / cron job, cleanbot executes silently in less than 500 milliseconds, keeps the system clean, and logs its output without any manual overhead.
Small automations like this compound over time, freeing up mental bandwidth and keeping machines tidy automatically.