Multiplatform engine for macOS, Linux, and Windows. The classification logic lives in a Rust binary; the schedulers of each operating system only execute it.
There are three installation channels, all published from the same release tag:
# 1. crates.io
cargo install organiza
# 2. npm (wrapper with binaries per platform)
npm install -g @dallay/organiza
# 3. Docker (multi-architecture linux/amd64 + linux/arm64)
docker pull yacosta738/organiza
docker pull ghcr.io/dallay/organizaYou can also download your platform's binary from the assets of the GitHub Release.
Requires stable Rust:
cargo test
cargo build --releaseThe binary is built at target/release/organiza (organiza.exe on Windows).
The Configure, Install as service instructions, and the launchers in
platform/assume a source checkout (local build from the repository). Users who install viacargo install organizaor the npm wrapper@dallay/organizacan downloadconfig.example.tomland the launchers directly from the repository on GitHub.
mkdir -p "$HOME/.config/organiza"
cp config.example.toml "$HOME/.config/organiza/config.toml"On Windows, copy the file to %APPDATA%\\organiza\\config.toml. Edit the folders and run:
# macOS/Linux
organiza --config ~/.config/organiza/config.toml validate-config
# Windows (PowerShell)
organiza --config $env:APPDATA\organiza\config.toml validate-configorganiza run --dry-run
organiza run
organiza run --verbose ~/Downloads
organiza run --config ./config.toml --log /dev/nullThe folders specified at the end replace source_directories. The default behavior waits 60 seconds, ignores hidden files, and renames conflicts (file (1).pdf).
organiza speaks English and Spanish. The interface language is resolved in this order:
--lang en|eson the command line (wins over everything).language = "en" | "es"in the config file.- The system locale (
LANG,LC_ALL,LANGUAGE). - English as the final fallback.
organiza --lang es run --dry-run
organiza --lang en --help# config.toml — pin the language so scripts are deterministic
language = "es"The binary ships seven flat English categories:
| Category | Extensions |
|---|---|
Text |
txt, md, rtf, doc, docx, pages, pdf, xlsx, xls, pptx, ppt, key, numbers, csv, epub, odt, ods, odp, log, tex |
Image |
jpg, jpeg, png, gif, webp, heic, svg, tiff, tif |
Video |
mp4, mov, mkv, avi, webm, m4v |
Audio |
mp3, m4a, wav, flac, ogg, aac |
Executable |
dmg, pkg, msi, exe, deb, rpm |
Compressed |
zip, rar, 7z, tar, gz, bz2, xz |
Other |
Everything else, including files without an extension and code/source files (.rs, .py, .js, .ts, …). Add a [[categories]] rule below to carve out a Code category if you want one. |
Files at the top of a source directory that are not one of the seven built-in folders are moved to Other/<dirname>/. Empty, symlinked, and (when ignore_hidden = true) hidden directories are skipped.
Add [[categories]] blocks to extend or replace the built-ins. Without replace, the rule supplements the built-in category. With replace = true, the rule substitutes the built-in list. [extensions] is applied last and wins over both:
# Add a new `Code` category without touching the built-ins.
[[categories]]
name = "Code"
extensions = ["rs", "py", "ts", "js", "go"]
# Replace the `Text` built-in with a single extension.
[[categories]]
name = "Text"
extensions = ["onlytxt"]
replace = true
# Per-extension overrides win last.
[extensions]
md = "Docs"If you run organiza run before creating a config file, the binary synthesizes Config::default() and auto-detects a Downloads directory. The lookup order is:
ORGANIZA_DOWNLOADSenv var (if set and the path exists).- Linux:
XDG_DOWNLOAD_DIRfrom~/.config/user-dirs.dirs. - macOS:
~/Downloads. - Windows:
%USERPROFILE%/Downloads, falling back to localized names (Descargas,Téléchargements,Scaricati,下载).
One-time reclassification of legacy folders. If you previously ran an older Spanish-defaults version, your ~/Downloads/Imágenes/, ~/Downloads/Documentos/, etc. will not be re-entered on the next run because only the seven English names are recognized as generated categories. Files inside those legacy folders are picked up once and moved under the new English-named categories. After that single pass, the legacy folders are empty and can be removed manually.
One-time path change after rebrand. The config directory moved from ~/.config/file-organizer to ~/.config/organiza (and %APPDATA%\\organiza on Windows), and the lock from ~/.cache/file-organizer.lock to ~/.cache/organiza.lock. Existing configs are not migrated automatically: copy your config.toml once to the new path and restart the scheduler. Legacy Downloads folders are handled as described above.
POSIX launchd and systemd schedulers that previously no-op'd (no config + no Downloads override) will begin organizing on each tick. The launchers in platform/ now invoke organiza run.
- macOS: use Shortcuts or
launchdto runorganiza run. - Linux: use the
systemduser timer included inplatform/linux/. - Windows: use Task Scheduler with
schtasks.
The lock is created with create_dir, so it does not rely on flock and works across all three systems.
mkdir -p "$HOME/.local/bin" "$HOME/Library/LaunchAgents"
cp target/release/organiza "$HOME/.local/bin/"
sed "s#YOUR_USERNAME#$(whoami)#" platform/macos/com.organiza.plist.example \
> "$HOME/Library/LaunchAgents/com.organiza.plist"
launchctl bootstrap "gui/$(id -u)" "$HOME/Library/LaunchAgents/com.organiza.plist"To stop it: launchctl bootout "gui/$(id -u)" "$HOME/Library/LaunchAgents/com.organiza.plist".
mkdir -p "$HOME/.local/bin" "$HOME/.config/systemd/user"
cp target/release/organiza "$HOME/.local/bin/"
cp platform/linux/organiza.service platform/linux/organiza.timer \
"$HOME/.config/systemd/user/"
systemctl --user daemon-reload
systemctl --user enable --now organiza.timerAfter copying organiza.exe to a permanent location (e.g., C:\Users\YOUR_USERNAME\.local\bin\organiza.exe) and creating the TOML at %APPDATA%\\organiza\\config.toml:
schtasks /Create /TN "organiza" /SC MINUTE /MO 5 `
/TR "C:\Users\YOUR_USERNAME\.local\bin\organiza.exe run" /FReplace YOUR_USERNAME with your actual Windows username, or adjust the path to match where you copied the executable.
The move operation uses rename, which is atomic within the same volume. If the source and destination are on different volumes, an error is reported instead of partially copying the file. When on_conflict = "overwrite" is configured and a cross-volume move fails, an existing destination file may be removed before the error is reported; for cross-volume safety, use on_conflict = "rename" or on_conflict = "skip".
Contributor setup for local quality gates, agent-instruction sync, and CI. The core package is Rust-only; the npm wrapper (npm/organiza) is a thin TypeScript launcher that ships the per-platform binaries as optional dependencies.
| Tool | Version | Install |
|---|---|---|
| Rust (stable) | pinned by rust-toolchain.toml (components: rustfmt, clippy) |
rustup.rs |
| Node.js | >= 18 (CI uses 22 LTS; local 24 works) | nodejs.org or fnm/nvm |
| Lefthook | 2.1.10 | macOS/Linux: brew install lefthook; Windows: winget or scoop; Linux distros: Debian/RPM/Alpine/Arch packages — see lefthook docs for the exact package name per system |
| AgentSync | 1.45.2 (@dallay/agentsync on npm) |
invoked via npx, no global install needed |
lefthook install # register git hooks from lefthook.yml
npx --yes @dallay/agentsync@1.45.2 apply # create generated instruction symlinksHealth check — run this locally to confirm generated instruction symlinks are in sync; CI runs the same command and fails on drift:
npx --yes @dallay/agentsync@1.45.2 status --jsonpre-commit:cargo fmt -- --check— blocks on unformatted code.pre-push:cargo clippy --all-targets --all-features -- -D warnings, thencargo test— blocks on failures.post-checkout,post-merge,post-rewrite:npx --yes @dallay/agentsync@1.45.2 apply || true— non-blocking refresh; a missing/broken AgentSync only surfaces viaagentsync status --json.
.agents/AGENTS.md is the single canonical source. agentsync apply creates symlinks at AGENTS.md (repository root), CLAUDE.md, and .github/copilot-instructions.md. Generated destinations are ignored through the marker-managed block in .gitignore; ordinary ignores (target/, .DS_Store) live outside that block. OpenCode consumes the root AGENTS.md and has no separate target; no MCP config is generated.
All third-party actions are pinned to full commit SHAs with a version comment.
quality(ubuntu):cargo fmt -- --checkandcargo clippy --all-targets --all-features -- -D warnings.test(ubuntu, macos, windows):cargo test.agentsync(ubuntu): runsagentsync apply --no-gitignorein an isolated copy of the checkout so.gitignoreis never persisted to the committed state, thenagentsync status --jsonas the blocking drift assertion. Windows CI never creates AgentSync symlinks.
Tool versions are pinned in this repository (see the table above; rust-toolchain.toml pins the Rust channel). Any version bump is a deliberate change requiring maintainer review. GitHub Actions are referenced by full commit SHA with a version comment; update the SHA and the comment together.
AgentSync uses symbolic links. On Windows, creating symlinks requires Developer Mode or elevated privileges (see Microsoft: enable your device for development). CI does not require symlink creation on Windows; contributors should run agentsync status --json after apply to confirm the sync worked.
Every third-party action is pinned to a full commit SHA with a version comment; external tools (cross, Node/npm, Docker buildx/QEMU) are pinned to exact versions. Nothing publishes until every preceding job passes.
Jobs, in order:
release-please— opens/updates the release PR (release-type rust, componentorganiza), bumpsCargo.tomland the npm wrapper versions, and creates the GitHub Release with theorganiza-<version>-<target>binaries +.sha256assets.build-binaries(8 targets) — linux x86_64/aarch64 (gnu + musl, cross-compiled withcross), darwin x86_64/aarch64, windows x86_64/aarch64. Uploads archives as workflow artifacts.upload-assets— attaches the archives to the GitHub Release.publish-npm-binaries(6 platform packages@dallay/organiza-<os>-<arch>) — gated on release-please result success; publishes with--provenance.publish-npm-base— publishes@dallay/organiza(wrapper), gated on the six platform packages succeeding.publish-crates—cargo publish --lockedfor theorganizacrate.publish-docker— multi-arch image (linux/amd64,linux/arm64) to Docker Hubyacosta738/organizaand GHCRghcr.io/dallay/organiza, taggedsemver+latest.release-summary— aggregates the results of every publish job.
Secrets required (repo/organization secrets, or the configured environment):
| Secret | Used by |
|---|---|
GH_APP_ID, GH_APP_PRIVATE_KEY |
release-please (create-github-app-token) |
NPM_TOKEN |
publish-npm-* |
CARGO_REGISTRY_TOKEN |
publish-crates |
DOCKERHUB_TOKEN (with DOCKERHUB_USERNAME) |
publish-docker |
GHCR_TOKEN |
publish-docker (GHCR) |
workflow_dispatch with dry_run: true runs the pipeline end-to-end without publishing or attaching assets.
Release rollback. If a release is published with an error:
- npm:
npm unpublish @dallay/organiza@<version> --forcewithin 72 hours of publish (and the corresponding@dallay/organiza-<os>-<arch>packages). - crates.io:
cargo yank --version <version>(crates.io does not allow deletion). - Docker: re-tag the previous good image as
latestand, if needed, remove the bad semver tag from both registries. - GitHub: delete the Release (and its assets) for the bad tag.
To remove the tooling:
- Delete
.github/workflows/ci.yml,.github/workflows/release.yml,lefthook.yml,rust-toolchain.toml,release-please-config.json,.release-please-manifest.json,Dockerfile,.dockerignore,npm/,scripts/, and.agents/. - Run
lefthook uninstallto remove the registered git hooks. - Remove the
# START AI Agent Symlinks/# END AI Agent Symlinksblock from.gitignore(keeptarget/,.DS_Store, and the npm ignores if desired). - Restore the reviewed root
AGENTS.mdfrom version control: its content is committed in.agents/AGENTS.md, sogit show HEAD:.agents/AGENTS.md > AGENTS.md(after step 1) restores the file.
No application code or Cargo dependency rollback is required.