All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Phase 1 — Core Scanning
- Recursive directory scanning with depth limits and
.forgeignorepatterns - Content extraction from 30+ file formats (text, PDF, DOCX, XLSX, HTML, images)
- SHA-256 exact duplicate detection with chunked hashing
- AI classification via local Ollama (qwen3:4b model)
- Rich terminal reports with category grouping and space estimates
- SQLite session persistence for scan history
Phase 2 — Advanced Analysis
- Near-duplicate detection via embeddings (nomic-embed-text + cosine similarity)
- Stale file detection based on modification age and junk patterns
- Version supersession detection (e.g.,
report_v1.docx→report_v2.docx) --phase-2flag to enable advanced features
Phase 3 — Interactive Actions
- Interactive HTML reports with per-file action buttons
fileforge organizecommand for automatic file organizationfileforge dupescommand for duplicate management- Dry-run mode for previewing actions
- Trash staging with date-based organization
- Action logging for undo support
Phase 4 — Background Automation
fileforge watchfor continuous filesystem monitoringfileforge schedulefor cron-based automated scans- Systemd integration with service and timer units
- Job audit trail for scheduled executions
- NameError bug in organize command (record.id scope issue)
- Silent exception handling in extract_snippet (now logs specific errors)
- Missing forgeignore error handling in organize and dupes commands
- Broad exception catches replaced with specific handlers
- All file operations use safe path handling
- No credentials or secrets in code
- Graceful degradation when AI services unavailable
- Comprehensive docs/ folder with overview, architecture, setup, API reference
- Tech stack documentation with dependencies and requirements
- Updated README with quick start guide
fileforge-server.servicesystemd unit for the long-running web UIinstall.sh --scan|--server|--allmodes in the systemd installer- Top-level
scripts/install.shnow offers to register systemd services scripts/release.shverifies systemd templates are present before packaging
CLAUDE.md— repository guidance for Claude Code sessions
scanner.py: replacePath.is_dir/is_file(follow_symlinks=False)(Python 3.13+) withos.pathequivalents for Python 3.11/3.12 compatibility
scripts/release.sh: stagesCHANGELOG.mdin the release commit and fails fast if the version entry is missingscripts/install.sh: fixes missing blank line before the Development quick-start block
api/server.py:/api/healthendpoint returned hardcoded"version":"0.1.0"; now reflects__version__from the packagesystemd/fileforge-scan.timer: duplicateOnCalendar=directives caused the daily scan to fire at midnight AND 02:00; consolidated toOnCalendar=*-*-* 02:00:00
scripts/install.sh: systemd installer lookup now falls back to pip-installed package location when the dev-tree path is absent
api/server.py:POST /api/scanrejected paths containing~(e.g.~/Documents) with HTTP 400; now calls.expanduser()before validation and subprocess invocationfrontend/index.html: category filter dropdown compared raw LLM category paths (e.g."Documents/Reports") against hardcoded keys ("document") — always false, hiding all rows; addednormalizeCategoryKey()to map free-text paths to filter keysfrontend/index.html: category colour dot never rendered becausegetCategoryColor()was a literal string inside a CSSstyleattribute; now evaluated in JS before HTML injectionfrontend/index.html: switching tabs did not sync the status<select>dropdown, leaving it showing a stale value
frontend/index.html: "Quick scan (skip AI classification)" checkbox (checked by default) so web UI scans complete in seconds rather than hours on large directoriesdb.py:complete_session()setscompleted_attimestamp on scan/organise/dupes finish; included inlist_sessions()response
api/server.py:POST /api/scanis now non-blocking — returns immediately with ajob_id; clients pollGET /api/job/{job_id}for statusapi/server.py: addedGET /api/browse?path=directory browser endpoint for the path-picker widgetpackaging: upgradedpackaginglibrary to 26.2 to support Metadata-Version 2.4 (License-Filefield) in twine checks
api/server.py+db.py:GET /api/session/{id}returned all records with no limit; sessions with millions of files sent a multi-GB JSON payload that froze the browser. Endpoint now accepts?limit=500&offset=0query params (default: first 500). Response includestotal,limit,offsetfields for pagination awareness.frontend/index.html: page load fetches only first 500 records on large sessions; shows warning toast when session is truncated (e.g. "Showing first 500 of 2,417,064 files").stat-totalcounter reflects session total, not truncated slice.
db.get_session_file_count(session_id)— COUNT query returning total records without fetching rowsdb.get_session_records()now acceptslimit(default: 500) andoffset(default: 0) parameters- Tests for
get_session_recordspagination andget_session_file_countintests/test_db.py
- Comprehensive docs overhaul: all files updated to v0.1.7 (were stuck at 0.1.0)
docs/Blueprint_Overview.html: branded single-page HTML reference (open in browser)docs/gap-analysis.md: tracks code vs. documentation discrepancies and planned featuresdocs/api.md: removed fictionalactions/logger.pysection; added complete REST API referencedocs/architecture.md: corrected module table (removedxlsx.py,html.py,image.pythat don't exist); added web server diagram and async scan data flowdocs/tech-stack.md: addedfastapi,uvicorn,Jinja2,packagingentries; clarified which formats have extractors vs. installed dependencies onlydocs/setup.md: correctedfileforge[ui]→fileforge[web]; addedfileforge servercommand reference- Removed stale
docs/superpowers/plans/planning docs (phases 2–4 are implemented) src/fileforge/api/__init__.py: added missing package init filescripts/install.sh: addedBlueprint_Overview.htmlandgap-analysis.mdto docs output
- Phase 5: React PWA GUI
- Phase 6: Cross-device sync
- Additional extractor formats (RTF, EPUB, xlsx, OCR)
- Custom classification models via config