█████▄ ▄███▄ █▓▄██▄ █▓███▄ ▄███▄ ▄█████ ▄███▄ ███▓██ ██ ██ ▓▒ ▀▒▓ ▓▒▀ ▀▒▓ ▓▒▀ ▀▒▓ ▓▒ ▀▒▓ ▓▒▀ ▀▒▓ ▓▒▀ █▒ ▓▒▀ ▀▒▓ ▓▒ ▓▒ ▒▓ ▒░ ░▒ ▒░ ░▒ ▒░ ░▒ ▒░ ░▒ ▒░ ░▒ ▒░ ▒░ ░▒ ▒░ ▒░ ░▒ ░ ▄ ▀ ░ ░ ░ ░ ░ ░ ░ ░ ░ ██░ ░ ░ ░ ░ ░ ░ ▄ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░▒ ▀▒░ ░▒ ▒░ ░▒ ▒░ ░▒ ▒░ ░▒ ▒░ ░▒ ░▒ ░▒ ▒░ ░▒ ░▒ ▒░ ▒▓ ▓▒ ▒▓ ▓▒ ▒▓ ▓▒ ▒▓ ▓▒ ▒▓ ▓▒ ▒▓ ▓▒ ▒▓ ▓▒ ▒▓ ▒▓ ▓▒ ▓█ █▓ ▓█ █▓ ▓█ █▓ ▓█ ▄█▓ ▓█▄ ▄█▓ ▓█▄ █▓ ▓█▄ ▄█▓ ▓█ ▓█ █▓ ██ ██ ██ ██ ██ ██ ██████▀ ▀███▀ ▀█████ ▀███▀ ██ ██ ██
════════════════════════════════════════════════════════════════════════════════
Node 1 · 2400 baud · 42 msgs in 6 areas · sysop randogoth
════════════════════════════════════════════════════════════════════════════════
════════════════════════════════════════════════════════════════════════════════
Msg : orvanitag-v2 Area : MINIMAL From : randogoth Date : 25 Oct 2026 Subj : otag 2: Plain-Text Tags for Your Files Keys : python, orvanitag, todo.txt
Msg : orvanitag-v2
Area : MINIMAL
From : randogoth
Date : 25 Oct 2026
Subj : otag 2: Plain-Text Tags for Your FilesKeys : python, orvanitag, todo.txt
════════════════════════════════════════════════════════════════════════════════
In June 2023 I spent one week writing a file tagger and then didn't touch it again for over three years. It is called Orvani Tagger, after עוֹרְבָנִי, the Hebrew name for the Eurasian jay, and the idea was simple: tag files the way todo.txt tags tasks. A +project, an @context, some #tags and a free note, typed on one line, searchable from the shell.
The 2023 version kept those tags in a .context.yaml in every folder, with a .index.yaml cache next to it and a configurable schema on top.
Version 2 throws the YAML out. Each folder now has a plain .otag file, and every line in it is written in exactly the syntax you type on the command line:
Boombap Loop.wav --- +album @drums #boombap #lofi
song.mp3 --- +album @drums #lofi #snare first take
stems/ --- @archive
You can open it in any editor, grep it, diff it, and it travels with the folder when you copy, sync or zip it. A line without the --- separator stops otag with an error naming the file and the line, so a typo of mine can't quietly eat the rest of the folder. The configurable schema is gone too.
The part that grew most is the plugins, from five to nine. scan reads tags that are already embedded in files and write puts them back, each in the place its format already has for it: the comment tag of an MP3 or FLAC, the keywords field of a PDF, the description of an ODT or DOCX, a COM segment in a JPEG, an iTXt chunk in a PNG, the archive comment of a ZIP, a pax header in a tar, a <meta name="otag"> in an EPUB, an otag: comment line at the top of a Python or Rust file. TagSpaces sidecars are read and written as well, so the two tools can share a folder. In every case the file's own data stays untouched, and another tool's comment (like the commit id git archive stores in a ZIP) is never overwritten.
The rest is housekeeping I had been putting off since 2023: setup.py and requirements.txt replaced by a pyproject.toml and uv, a committed build/ directory deleted, the CLI rebuilt on argparse with one handler per command, a real test suite, and the licence moved from MIT to Apache-2.0. There is also a SKILL.md, so a coding agent can tag and search files with it without me explaining the syntax every time.
It's not on PyPI yet. For now it lives in the repository below.
--- RANDOGOTH BBS * Origin: randogoth.com (1:1/1)
────────────────────────────────────────────────────────────────────────────────
[I]ndex [K]eywords [F]eed Main [M]enu
Command: