An autonomous agent that ranges, classifies and archives the files and folders on a machine (Downloads, Desktop, projects…) according to rules you control. It previews everything in dry-run by default, never deletes your data, and every executed run is fully reversible.
How is this different from a backup pack?
| agent-organizer-v1 (this pack) | agent-backup-v1 | |
|---|---|---|
| Goal | tidy a messy disk: sort, classify, archive | protect data: snapshots + restore |
| Core action | move/copy files into a tidy tree | copy into timestamped backups |
| Classification | extension / date / name / size / LLM | n/a |
| Archiving | compress stale folders into YYYY-MM/ |
scheduled full snapshots + retention prune |
| Reversibility | JSON journal + --rollback of every move |
restore from a snapshot |
| Deletes data? | never | never |
They are complementary: organize your disk, then back it up.
Architecture
+------------------+ +------------------+ +------------------+
| Rules (YAML) | --> | SCANNING | --> | CLASSIFYING |
| source/target/ | | white/black list | | ext|date|name| |
| classify_by | | recursive? | | size|llm |
+------------------+ +------------------+ +--------+---------+
|
+----------------------------+
|
+---------v----------+ +----------v---------+
| ORGANIZING | | ARCHIVING |
| move/copy -> | | stale folders -> |
| target/<category>/ | | archive/YYYY-MM/ |
+---------+----------+ +----------+---------+
| |
+---------v----------+ +----------v---------+
| LOGGING (JSON) | | REPORTING |
| journal_*.json | ---> | --rollback undo |
+--------------------+ +--------------------+
One-shot install (Debian/Ubuntu)
unzip agent-organizer-v1.zip && cd agent-organizer-v1
sudo bash install.sh # system deps + venv + daily systemd timer (DRY-RUN)
The timer runs the organizer in dry-run so it never moves files unattended.
Review the plan in journalctl -u agent-organizer-v1 -f, then edit the unit's
ExecStart to add --execute when you trust it.
No root / no systemd?
bash install.sh --no-servicesets up the venv, then run the commands below by hand.
Quick commands
python agent.py --help
python agent.py --dry-run --config templates/organizer_rules.yaml # preview (default)
python agent.py --execute --config templates/organizer_rules.yaml # apply moves/copies
python agent.py --execute --archive-old 90d --config templates/organizer_rules.yaml
python agent.py --rollback journal_20260710_120000.json # undo a run
bash smoke_test.sh
Classification modes (classify_by)
| Mode | Destination | Example |
|---|---|---|
extension |
target/<category>/ |
report.pdf → Organized/documents/ |
date |
target/YYYY/MM/ |
modified 2026-03 → Organized/2026/03/ |
name |
first matching name_rules |
invoice_* → Organized/finance/ |
size |
small / medium / large |
2 GB video → Organized/large/ |
llm |
LLM-chosen category (optional CLI) | ambiguous name → best-fit folder |
Safety by design
- Dry-run default — nothing changes until
--execute. - Never deletes — only move, copy, or compress-into-archive.
- Protected paths — refuses
/,/etc,/usr,/root/.ssh,~/.config… - White-list / black-list — skip explicit patterns and paths.
- Confirmation gate — sources above
confirm_overfiles require--yes. - Reversible — every executed run journals to JSON;
--rollbackundoes it. - Collision-safe — never overwrites; appends
_1,_2… on name clashes.
Connect your LLM (optional, no API key)
Set classify_by: llm and connect one coding-agent CLI:
| CLI | Install | Connect |
|---|---|---|
| Claude Code | npm i -g @anthropic-ai/claude-code |
run claude, /login |
| Kimi Code | see platform.moonshot.ai | kimi-code |
| Codex | npm i -g @openai/codex |
codex login |
Force one with PACK_LLM=claude|kimi|codex. If none is connected, the
deterministic classifier runs — the agent never blocks.
Contents
| File | Purpose |
|---|---|
agent.py |
Runnable organizer — scan, classify, organize, archive, journal, rollback |
llm_adapter.py |
BYO-LLM CLI adapter (claude/kimi/codex), no API key |
templates/organizer_rules.yaml |
Editable rules (paths, classify_by, lists, maps) |
install.sh |
One-shot Debian installer (deps + venv + safe dry-run timer) |
agent-organizer-v1.service |
Reference systemd unit (install.sh generates the real one) |
smoke_test.sh / test_agent.py |
Offline test suite (deterministic) |
PROMPTS.md |
Classifier / Archive-advisor prompts loaded by the agent |
SPEC.md |
Technical spec + rules schema |
CHECKLIST.md |
22-step deploy & operate checklist |
CUSTOMIZE.md |
5-minute guide to plug in your folders & rules |
OPERATING_COST_ESTIMATE.md |
Provider-agnostic LLM cost estimate ($0 in default mode) |
CHANGELOG.md |
Version history |
README.md |
This file |
requirements.txt |
Python deps (stdlib core + optional PyYAML) |
deploy.sh |
Thin wrapper → install.sh |
agent-organizer-v1.json |
Pack manifest |
Use a local model (Ollama)
The optional LLM step can also run on your own machine through Ollama, so no text leaves your server. No account and no API key.
ollama pull <model> # any chat model you like
export PACK_LLM=ollama # prefer Ollama even if a coding-agent CLI is installed
export PACK_OLLAMA_MODEL=<model> # optional: default is the first chat model the server lists
python3 -c "import llm_adapter; print(llm_adapter.detect())" # prints: ollama
PACK_OLLAMA_HOSTpoints to another server (defaulthttp://127.0.0.1:11434);OLLAMA_HOSTis also read whenPACK_LLM=ollama.PACK_OLLAMA_NUM_CTXsets the context size if your reports or prompts are long.- Without
PACK_LLM, a local Ollama server is used only when no Claude Code, Kimi Code or Codex CLI is found. - If the server is down or the model is missing, the pack keeps working in its deterministic mode.
Learning memory (local and private)
Every LLM call this pack makes is journaled in ./.pack_memory/ next to the code, so the pack can improve for you. Nothing is ever sent anywhere.
- What is kept: the task name, the masked input, the masked answer, status and latency. Keys, tokens, e-mails, phone numbers, IP addresses, card and IBAN numbers and personal paths are masked before writing; the system prompt is never stored.
- Teach it:
python3 pack_memory.py feedback last okconfirms a result,python3 pack_memory.py feedback last bad --fix "the right answer"corrects it. Confirmed and corrected runs are reused as validated examples when a similar input comes in. Unrated runs are never injected into a prompt. - Find similar cases:
python3 pack_memory.py similar "some text"andpython3 pack_memory.py clusters(groups of near-identical failures) work in plain Python, no model needed. Optional meaning-based matching uses an embedding model you already run locally:python3 pack_memory.py enable-semantic(Ollama on this machine only). - Share, only if you want:
python3 pack_memory.py exportwrites an anonymised summary (counts, statuses, size buckets, no text) for you to review. - Control:
PACK_MEMORY=0turns it off,PACK_MEMORY_STORE_TEXT=0keeps fingerprints only,python3 pack_memory.py purge --yeswipes it.
