diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-09-13 02:31:32 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-09-13 02:31:32 +0200 |
| commit | 26c94eb3db62ec6eebbf8d22c11afe691d9520c4 (patch) | |
| tree | 165e5bf69234b4f96c9b74deb4898d7143ddf120 /README.md | |
| parent | a6e442a645902011b2081c216daaec052cdc6ce6 (diff) | |
| download | krino-0.0.1.tar.gz krino-0.0.1.zip | |
krino: release 0.0.1 — man pages, install, examples, cross and release, README, changelogv0.0.1
Also: undo removes the directories its run created; a hardlink is never a
duplicate of its own other name; a flag written before "undo" is honoured;
--version prints no leading v. Duplicate conditions with different scopes
not sharing an original is documented as a known limitation.
Diffstat (limited to 'README.md')
| -rw-r--r-- | README.md | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/README.md b/README.md new file mode 100644 index 0000000..4b7d4c3 --- /dev/null +++ b/README.md @@ -0,0 +1,214 @@ +# krino + +krino sorts the files in one or more directories by rules: conditions on a +file's type, name, path, size, age, text content or duplicate status, +combined with `and` / `or` / `not`, that trigger actions — copy, move, +rename, delete (to the Trash by default), chained in the order written. It +shows the plan before touching anything, lets you approve all of it or file +by file, logs every step, and can undo a run. Version 0.0.1 is the engine +and this command-line interface: per-directory rule files, placeholders in +destinations and new names, and builds for Linux, FreeBSD and OpenBSD. It is +not a GUI (that comes later), a watch mode, OCR, EXIF dates, macOS or +Windows support, a content cache, a shell-command action, or a way to look +inside archives. + +## Install + +``` +make && make install +``` + +`make` builds `./krino`; Go fetches the module dependencies itself. `make +install` puts the binary in `$PREFIX/bin` (default `~/.local/bin`), the man +pages in `$PREFIX/share/man`, and the examples and `docs/sexp-primer.md` in +`$PREFIX/share/doc/krino`. + +Some `(content ...)` tests need external extractors — `pdftotext` for PDF, +`antiword`/`catdoc` for legacy Word, `xls2csv`/`catppt` for legacy Excel and +PowerPoint. `make build` reports which of these are missing; install them +with: + +``` +make deps +``` + +`make deps` is the only target that asks for privileges — it calls the +system package manager (`apt-get`, `pkg`, or `pkg_add`, depending on the +OS). Plain `make` never does. + +## The 60-second quickstart + +Everything below happens in `/tmp/krino-demo` and a scratch config under +`/tmp/krino-xdg`, so it never touches a real directory or your real krino +config. Copy-paste it as written and your output should match what's pasted +here, except for the run id and timestamps, which are different every time. + +Create a handful of files of different types: + +``` +mkdir -p /tmp/krino-demo +cd /tmp/krino-demo +for f in acme-invoice.pdf photo.jpg podcast.mp3 archive.zip app.deb notes.txt; do + printf 'demo file: %s\n' "$f" >"$f" +done +``` + +Point krino at a scratch config for this walkthrough: + +``` +export XDG_CONFIG_HOME=/tmp/krino-xdg/config +export XDG_STATE_HOME=/tmp/krino-xdg/state +export XDG_DATA_HOME=/tmp/krino-xdg/data +``` + +Set it up: + +``` +$ krino init +created /tmp/krino-xdg/config/krino/krino.conf +created /tmp/krino-xdg/config/krino/template.conf +next: krino new NAME PATH, for example: krino new downloads ~/Downloads +$ krino new demo /tmp/krino-demo +created /tmp/krino-xdg/config/krino/dirs/demo.conf and added "demo" to include +edit its rules, then check them with: krino check demo +``` + +`krino new` copied the template to `dirs/demo.conf` and filled in the path. +Replace its body with a small rule. The built-in `min-age` is 2 minutes +(files skip as "busy" while they might still be downloading), which the +demo files we just created are younger than, so this also turns it down to +0 for this directory: + +``` +cat > "$XDG_CONFIG_HOME/krino/dirs/demo.conf" <<'EOF' +;; -*- mode: lisp -*- +;; vim: set ft=lisp : + +(path "/tmp/krino-demo") +(min-age 0s) ; demo files are seconds old; built-in is 2m + +(rule "acme" + (when (name "acme")) + (move "Filed/Acme")) +EOF +``` + +This one rule matches any file whose name contains "acme" and moves it into +`Filed/Acme`. See what it would do, without changing anything: + +``` +$ krino -n demo +krino: demo /tmp/krino-demo +6 scanned · 1 to act on · 0 warnings · 0.00s + + # file actions rule + 1 acme-invoice.pdf move → Filed/Acme/ acme name "acme" + +not acted on: 5 unmatched (-v lists them) +``` + +Without `-n` or `-y`, `krino demo` shows the same plan and then asks, one +key at a time, no Enter needed: + +``` +[a] apply all [c] choose per file [s] skip this directory [q] quit +``` + +`c` asks about each file in turn: + +``` + [y] yes [n] no [a] yes to this and all remaining [d] done, apply chosen so far [q] quit, apply nothing +``` + +Approval is per file: a file's whole chain runs, or none of it. A README +can't paste a session it didn't actually run in a terminal, so here we +apply directly with `-y`, which shows the same plan and applies it without +asking: + +``` +$ krino -y demo +krino: demo /tmp/krino-demo +6 scanned · 1 to act on · 0 warnings · 0.00s + + # file actions rule + 1 acme-invoice.pdf move → Filed/Acme/ acme name "acme" + +not acted on: 5 unmatched (-v lists them) +1 applied · 0 failed · 0 declined +``` + +`acme-invoice.pdf` is now in `Filed/Acme/`. Every run is logged: + +``` +$ krino log +20260913T005509-db14 2026-09-13 00:55 demo 1 moved +``` + +And every run can be undone — `undo` alone would show its own plan and ask +the same way, with a menu of its own: + +``` +[a] apply all [c] choose per file [s] skip [q] quit +``` + +`-y` applies it directly: + +``` +$ krino undo -y +krino: undo 20260913T005509-db14 +1 files · 1 to reverse · 0 refused + + # file steps + 1 demo/acme-invoice.pdf undo-move → /tmp/krino-demo/acme-invoice.pdf + undo-mkdir /tmp/krino-demo/Filed/Acme + undo-mkdir /tmp/krino-demo/Filed +1 applied · 0 failed · 0 declined +``` + +`/tmp/krino-demo` is back exactly as the first `printf` loop left it — that +is what `krino undo` is for. Delete both scratch directories when you're +done: `rm -rf /tmp/krino-demo /tmp/krino-xdg`. + +## Configuration + +Rules are s-expressions. `docs/sexp-primer.md` is a short tutorial on the +syntax with no Lisp background assumed; `krino.conf(5)` (`man/krino.conf.5` +in the source, installed as a man page) is the reference for every form, +setting and condition. `examples/` has four worked rule files: by type, by +content (invoices), by age (old installers), and renaming (screenshots). + +Rules live in `$XDG_CONFIG_HOME/krino` (default `~/.config/krino`) — +**never in this repository**. A leak check guards that: it runs in `make ci`, +and on every commit only after `make install-hooks`. It refuses staged files +that contain your home directory's path or an email address, and it catches +rule content only when a private pattern list is configured with +`git config krino.leakpatterns FILE`. + +## Safety + +- `(delete)` moves a file to the freedesktop.org Trash by default, not + `unlink(2)` — recoverable, by hand or with `krino undo`. `(delete + permanent)` is the explicit opt-out, and undo can never reverse it. +- Every step of every run is appended to `$XDG_STATE_HOME/krino/krino.log` + (default `~/.local/state/krino/krino.log`), tab-separated and + `grep`-able. +- `krino undo` reverses the most recent run, or a specific one by id from + `krino log`. A reversal that the world has moved on since (the target is + gone, changed, or the original path is occupied again) is refused for + that file rather than guessed at. +- `-n` prints the plan and changes nothing, ever — no config is written, no + file is touched, nothing is logged. + +## Status + +**0.0.1, local only.** The module path is `krino`; `go install +krino@v0.0.1` only works once a remote is chosen and the imports are +renamed to match (`docs/design.md`, §18). Until then, build from a clone. +`krino -n --json`'s output shape is unstable before krino 1.0 — don't +script against it yet. + +## License + +Everything in this repository — code, man pages, examples and the embedded +templates — is GPL-3.0-or-later. Full text in `LICENSE`. Go files, shell +scripts and man pages carry an SPDX identifier. |
