- Python 67%
- HTML 33%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
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 |
||
| elements | ||
| filegoblin | ||
| handoff | ||
| materials | ||
| Test | ||
| .gitignore | ||
| filegoblin.desktop | ||
| filegoblin.service | ||
| index.md | ||
| INSTALL.md | ||
| LiveTestResults.txt | ||
| pyproject.toml | ||
| README.md | ||
| test_filegoblin.py | ||
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.