No description
  • Python 67%
  • HTML 33%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Photonamus cfbc365ae5 Add classification and tracing handoff; update project state
Handoff chunk for the session that fixed media being skipped and added trace
logging. Records the three separate causes behind one symptom, the nine
decisions taken, and the name-mangling risk to watch during the model
comparison.

Project state moves from soak to model comparison. Naming is recorded as the
known gap with the human's two-pass proposal captured for v2, so the next
session does not rediscover it. LiveTestResults.txt is committed as the record
of the failing run the fix was measured against.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wpy6eCcm52oySrxmiqpdFU
2026-09-06 22:17:42 -04:00
elements initial commit 2026-09-06 08:15:57 -04:00
filegoblin Fix media being skipped; add model trace logging 2026-09-06 22:00:53 -04:00
handoff Add classification and tracing handoff; update project state 2026-09-06 22:17:42 -04:00
materials initial commit 2026-09-06 08:15:57 -04:00
Test Build steps 1-8: config, classifier, mover, daemon, CLI 2026-09-06 09:09:34 -04:00
.gitignore Build steps 1-8: config, classifier, mover, daemon, CLI 2026-09-06 09:09:34 -04:00
filegoblin.desktop Build steps 11-12: systemd unit, autostart, install docs 2026-09-06 09:29:38 -04:00
filegoblin.service Build steps 11-12: systemd unit, autostart, install docs 2026-09-06 09:29:38 -04:00
index.md Add classification and tracing handoff; update project state 2026-09-06 22:17:42 -04:00
INSTALL.md Build steps 11-12: systemd unit, autostart, install docs 2026-09-06 09:29:38 -04:00
LiveTestResults.txt Add classification and tracing handoff; update project state 2026-09-06 22:17:42 -04:00
pyproject.toml Build steps 1-8: config, classifier, mover, daemon, CLI 2026-09-06 09:09:34 -04:00
README.md Fix media being skipped; add model trace logging 2026-09-06 22:00:53 -04:00
test_filegoblin.py Fix media being skipped; add model trace logging 2026-09-06 22:00:53 -04:00

File Goblin

A background daemon that watches a folder and files what lands there, using a local model via Ollama. No cloud, no API keys. When it isn't sure, it leaves the file alone and tells you why — it never guesses destructively.


Status on this machine

Already installed and running. It starts at login and is watching right now.

Drop files here ~/Downloads/Inbox
Files land here ~/Downloads/Sorted
Config and logs ~/.filegoblin/
Model in use qwen2.5:7b
Confidence threshold 0.80

Commands

Run these from anywhere.

filegoblin status

Where things stand: inbox path, how many files are waiting, how many were sorted today, how many need review, when it last did anything. Start here.

filegoblin sort --dry-run

Shows what it would do to everything in the inbox. Moves nothing. This is the safe way to check behaviour after changing a rule, the threshold, or the model.

filegoblin sort

Processes everything waiting in the inbox now. You rarely need this — the daemon already does it — but it's useful after the daemon has been stopped.

filegoblin check

The teach loop, and the main thing you'll use. Walks through files it couldn't place and asks what to do with each one. Answer in plain English:

put KiCad and PCB design files into Electronics/PCB and keep the original name

It writes the rule into conventions.md, backs the file up first, and offers to sort the waiting file immediately. Press s to skip a file, q to quit.

filegoblin undo -n N

Reverses the last N moves, newest first. Asks before doing anything; add -y to skip the prompt. It won't undo the same move twice, and it refuses if something else now occupies the original path.

filegoblin undo          # reverse the last move
filegoblin undo -n 5     # reverse the last five

filegoblin log -n N

Recent sort decisions with timestamps, confidence scores, and destinations.

filegoblin trace -n N

Shows the last N model exchanges: what the file looked like going in, what came back, and how long it took. Add -f to print the full prompt, conventions and all. This is the file to read when sorting goes wrong — the model's own reason line usually says exactly what it thought it was looking at.

filegoblin daemon

Runs the watcher in the foreground. Only useful for debugging — systemd already runs this for you.


Starting and stopping the service

systemctl --user status filegoblin      # is it running?
systemctl --user stop filegoblin        # stop until next login
systemctl --user start filegoblin       # start again
systemctl --user disable filegoblin     # stop starting at login
systemctl --user enable --now filegoblin  # start now and at every login
journalctl --user -u filegoblin -f      # watch what it's doing, live

Configuring it

Everything lives in ~/.filegoblin/conventions.md. Edit it in any text editor.

Changes take effect immediately. The file is re-read on every single file event, so a new rule or a new threshold applies to the next file that arrives. The one exception is inbox — the watcher binds to one directory, so changing that needs systemctl --user restart filegoblin.

Settings

confidence_threshold: 0.8
model: qwen2.5:7b
trace: on

confidence_threshold is how sure the model must be before a file is moved. Higher (0.9) means more caution and more files waiting for review. Lower (0.6) means more gets filed automatically and more gets filed wrong.

trace logs every prompt and response to trace.log. Leave it on while you are tuning categories to your own files; set it to off once the sorting is boring.

Paths

inbox: ~/Downloads/Inbox
output_root: ~/Downloads/Sorted
allowed_roots: ~/Downloads/Sorted

allowed_roots is the hard safety boundary. Any move landing outside it is refused and logged, no matter what the model decides. This is enforced in code — the model gets no say in it.

Categories

Plain English. Add as many as you like, or let filegoblin check write them:

### Invoices
Match: any file with 'invoice', 'receipt', or 'order' in the name
Destination: Finance/Invoices/YYYY/
Naming: YYYY-MM-DD_vendor_amount.ext (extract from content if possible)

Destination is relative to output_root. YYYY, YY, MM, and DD in a destination or a name are substituted in code from the file's date — taken from the filename if it carries one, otherwise from the file's own timestamp. The model never has to get that right.


Files it writes

File What it is
~/.filegoblin/conventions.md your config and rules — edit freely
~/.filegoblin/conventions.md.bak automatic backup, written before every rule change
~/.filegoblin/engine.prompt model behaviour — don't edit unless you mean it
~/.filegoblin/activity.log every move, as JSON lines. undo reads this
~/.filegoblin/unhandled.log files awaiting review. check reads this
~/.filegoblin/trace.log every prompt and response, while trace: on. trace reads this

Testing against other models

Switching models is one line in conventions.md and takes effect on the next file — no restart:

model: gemma3:12b

Then re-run the same set of files and compare:

filegoblin sort --dry-run

Use --dry-run so nothing moves and you can run the identical set against every model. Watch for: does it pick the right category, does it follow the naming rule, does it extract dates and vendors from file contents, and is its confidence honest — a model that says 1.00 on everything makes the threshold useless.

Installed and usable

Model Size Notes Result
qwen2.5:7b 4.7 GB current default, baseline
llama3.1:8b 4.9 GB general purpose
mistral:7b 4.4 GB general purpose
gemma3:12b 8.1 GB larger, slower
phi4:14b 9.1 GB largest installed; Phi models are strong at JSON
qwen2.5-coder:7b 4.7 GB code-tuned, may be weak at general classification
deepseek-coder-v2:16b 8.9 GB code-tuned, same caveat

nomic-embed-text is an embedding model, not a chat model. It cannot be used here.

Worth pulling — the actual ship targets

The design doc targets a ~200 MB idle footprint, and every model above is far bigger than that. These are the sizes File Goblin is meant to ship against, so they matter more than the big ones:

Model Size Pull command Result
qwen2.5:3b ~1.9 GB ollama pull qwen2.5:3b
qwen2.5:1.5b ~1.0 GB ollama pull qwen2.5:1.5b
phi3:mini ~2.3 GB ollama pull phi3:mini
gemma3:1b ~0.8 GB ollama pull gemma3:1b
llama3.2:3b ~2.0 GB ollama pull llama3.2:3b
llama3.2:1b ~1.3 GB ollama pull llama3.2:1b

If a pull 404s the tag has moved — check https://ollama.com/library for the current name.

Fill in the Result columns as you go and they carry into the next session.


When something goes wrong

It moved a file somewhere wrong. filegoblin undo, then filegoblin check to teach the correct rule so it doesn't repeat.

It isn't sorting anything. Check systemctl --user status filegoblin, then that Ollama is running (curl -s localhost:11434/api/tags). If Ollama is down the daemon keeps watching and logs each file as unhandled rather than guessing.

Everything is landing in unhandled. Either the threshold is too high or no category matches. filegoblin sort --dry-run shows the reasoning per file, and filegoblin trace -f shows the exact context the model was working from. The usual cause is a file type with no category at all — add one with filegoblin check.

It's sorting things it shouldn't. Raise confidence_threshold toward 0.9.

A rule broke the config. Every rule write backs up to conventions.md.bak first and rolls back automatically if the file no longer parses. To restore by hand: cp ~/.filegoblin/conventions.md.bak ~/.filegoblin/conventions.md.


Testing without touching real files

Point FILEGOBLIN_HOME at the sandbox in the project folder. It uses its own config, its own inbox, its own logs, and never touches ~/Downloads:

cd ~/orchestration/FileGoblin
FILEGOBLIN_HOME=Test filegoblin sort --dry-run

Run the code's own checks:

python3 test_filegoblin.py

Installing elsewhere

See INSTALL.md. Short version: pipx install -e ., copy filegoblin.service to ~/.config/systemd/user/, then systemctl --user enable --now filegoblin.