Repository navigation
Releases: rhsev/fileregister
Release list
fileregister 2.1.0
The bookmark store moved to ~/.local/share/fileregister/bookmarks.json. Versions before 2.1 kept it at ~/.local/share/bookmarks.json, a path the bookmark CLI shared; the store is now register's alone. There is no migration code. Move it once, before the first run of 2.1:
mkdir -p ~/.local/share/fileregister && mv ~/.local/share/bookmarks.json ~/.local/share/fileregister/Without the move, register 2.1 starts with an empty store and every record shows a broken bookmark. Nothing is lost, and the move puts it right.
cleanup offers orphan bookmark entries. An entry that resolves but that no record claims used to be left alone, since another tool might have held it in the shared store. With the store register's own, it is a leftover: cleanup lists it with the dead and malformed entries, and --prune drops it. audit counts orphans as findings and exits 1.
go install finds 2.x. The module path is now github.com/rhsev/fileregister/v2. Go needs the /v2 for a major version of 2 or higher; without it, @latest resolved to 1.4.0. To install from source:
go install github.com/rhsev/fileregister/v2/cmd/register@latest2.0.0 and 2.0.1 stay out of reach for go install; use the download or build from a checkout. Anyone who installed through the old path stays on 1.4.0 until they use the new command.
Upgrading from 2.0
- Move the bookmark store (above). The download's INSTALL.txt has the command too.
- From source: the new
go installpath.
Download (Apple Silicon): fileregister-macos-arm64.tar.gz bundles register with its two helpers in libexec/, the fileanchor 1.3.0 engine and grubber v0.19.0, plus each component's license in licenses/. Fetched with curl it runs as-is; after a browser download, clear the quarantine flag once in the unpacked folder: xattr -dr com.apple.quarantine register libexec. Intel Macs: build from source (go install + make fileanchor + make grubber).
License: PolyForm Noncommercial 1.0.0 (use, change, non-commercial).
fileregister 2.0.1
Detail adjustments, no new features. 2.0.1 comes from an end-to-end run of every subcommand on real files, with the real engine, grubber and Spotlight, in a sandbox: add, promote, annotate, aka, order, album, rename, remove, forget, refresh, repair, write, reindex, cleanup, and marshal with unmarshal into a second home and notes directory. Every step wrote what WHO-WRITES-WHAT.md says it writes, and no data was lost. The read-only commands also ran against a real collection of 200 records. The run turned up the changes below.
audit checks the id layer and exits 1 while something needs you. Besides the binder xattr, it now checks what refresh writes: the record id in kMDItemInformation, which repair looks up first, the same id in com.fileregister.id#S, and ★ on members. A file that lacks any of them is listed as missing id. Like refresh and repair, audit now exits 1 while there is something to fix, so a monitor can rely on it. Copies, orphan bookmarks and entries on an absent volume are reported but do not count.
audit counts records. A record in two binders counted twice in the summary.
refresh --dry-run reports what the real run would write. It used to list every membership, including names already on the file.
repair records a renamed file's new name on its index line, so list and album show the name the file has now. The id does not change, and note headings stay as they are.
unmarshal keeps a note staged until its records are imported. When every file of a container was parked, for instance without --scatter, the note used to land alone, with blocks pointing at ids the index did not have, and the rerun left a second copy in import/. Now the note waits and arrives with its records.
Clearer output. cleanup names an id once, rename counts index records and note blocks apart, list --inbox/--curated say what an empty result means, and repair says when a file it found waits for confirmation instead of calling it not found. SPEC now says that a record rebuilt by reindex or written by write has no bookmark until repair --interactive binds it.
Engine: fileanchor 1.3.0, which adds --version. The release script now asks every binary in the bundle for its version and stops on a mismatch.
Download (Apple Silicon): fileregister-macos-arm64.tar.gz bundles register with its two helpers in libexec/, the fileanchor engine and grubber v0.19.0, plus each component's license in licenses/. Fetched with curl it runs as-is; after a browser download, clear the quarantine flag once in the unpacked folder: xattr -dr com.apple.quarantine register libexec. Intel Macs: build from source (go install + make fileanchor + make grubber).
License: PolyForm Noncommercial 1.0.0 (use, change, non-commercial).
fileregister 2.0.0
Breaking: register album prints data, not HTML. The album is the binder in order as JSON lines: each member's list --json line plus position, fields (its block in the note, read through grubber) and file (what the file itself carries, such as size, date, place and coordinates). A gallery, a report or a web page is built from those lines by whatever reads them. The renderer and its flags (--out, --css, --milan, --open) are gone, and album says so when given one. See ALBUM.md.
Breaking: the note is the order. Members follow their blocks in the order they stand in the binder's note, so moving a block in the editor moves the member, and renaming a file moves nothing. A sort: key still places a member ahead of the document, and register order move writes them. order set and --rule are gone; a type: ordering block from earlier versions is harmless.
Breaking: grubber reads every note. register had its own small Markdown reader behind list --inbox/--curated, annotate, aka, marshal, reindex, rename and cleanup. These commands now read through grubber, as album and order do, so both sides see the same blocks. They need grubber v0.19.0 or later, which the download carries; the core commands run without it. register calls grubber with --no-config, so your grubber config does not change what register sees.
tags is no longer an index field. Free labels belong in the member's block, where grubber, matterbase and the album see them. write ignores a tags input field and says how many lines carried one. An index line that has the field keeps it, unread.
register forget takes a record in no binder out for good: the index line, the bookmark entry, and its id in the notes and on the file. The note blocks stay, and promote reattaches one if the file comes back. No other command deletes a record.
refresh puts a missing id back. iCloud Drive strips kMDItemInformation, the id Spotlight searches, and repair relies on it to find a renamed file. refresh now restores it wherever it is missing. It adds and never replaces, and writes nothing when there is nothing to restore.
list --json without a binder lists the binders, one {"name","count"} line each.
A bookmark is the macOS anchor, and only that. A record whose binder set is empty used to be called a bookmark. It is now a record in no binder, and the output says so: audit shows [no binder], cleanup lists "Records in no binder", and add without --binder reports "Registered in no binder". "URL ref" is now "URL record". Scripts that parse the human-readable output may need a look; --json output is unchanged.
Documentation. WHO-WRITES-WHAT.md shows what each command writes to the index, the bookmark store, the file and the notes. README, SPEC and the other documents were checked against the code. make install now also installs a grubber fetched with make grubber.
Upgrading from 1.x
- An HTML album needs a renderer of your own that reads
register albumlines. - An album that relied on file-name order: check it once with
register order show <binder>, then move blocks in the note or useregister order move. - grubber v0.19.0 goes next to register. The download has it; from source,
make grubber && make install. - Labels kept in an index
tagsfield belong in the blocks.
Engine: fileanchor 1.2.0, unchanged.
Download (Apple Silicon): fileregister-macos-arm64.tar.gz bundles register with its two helpers in libexec/, the fileanchor engine and grubber v0.19.0, plus each component's license in licenses/. Fetched with curl it runs as-is; after a browser download, clear the quarantine flag once in the unpacked folder: xattr -dr com.apple.quarantine register libexec. Intel Macs: build from source (go install + make fileanchor + make grubber).
License: PolyForm Noncommercial 1.0.0 (use, change, non-commercial).
fileregister 1.4.0
Albums are named in the note's frontmatter. An album gives a bundle an order; what it is called is one field. album: Safari, Namibia 2026 in the frontmatter of the binder's note, and every member inherits it, because grubber passes frontmatter down into each block of the file. The heading takes it from the members, and without the field it stays the binder name. register album safari --title "Safari, Namibia 2026" writes the field, editing the note by hand does the same, and grubber extract ~/notes -a -f album~Safari finds every member.
The identity layer is auditable. ~/.local/share/bookmarks.json holds id → bookmark and was the one store nothing could see into: both existing audit directions start from records, so an entry no record claimed was invisible, and the file only grew. register audit gains a third direction, Bookmark → Record, with four verdicts: orphan (resolves, no record claims it), broken (a file still carries the id, so register repair can re-bind it), dead (neither), and malformed (the key was never a minted id). register cleanup gains a matching section offering only the two beyond repair, and --prune drops them without asking.
--prune refuses rather than guess. "Dead" means the blob does not resolve and no file carries the id, which is only true if the question could be asked. An unmounted volume, or a mounted one Spotlight does not index, makes every bookmark on it look dead, so those entries are parked as unreachable and the prune declines, naming the volume. The same holds for the engine: without fileanchor 1.2.0's last_path the guard has nothing to judge, so the dead verdict is withheld entirely. The capability is measured, not read off a version number.
Engine: fileanchor 1.2.0, bundled in the download and required for the audit direction above. Resolving no longer mounts a volume or shows UI. It used to mount detached disk images on its own and could block on an unreachable network share. A failed resolve now names the path recorded in the bookmark, which is what separates a gone file from an absent volume. And the id attribute is stored as a property list: written as a raw string, two ids on one file made Spotlight drop the whole value, so the file could be found by neither.
grubber comes in the download. fileregister without grubber is the index; whenever the Markdown layer comes into play, grubber reads it. register album now does too, instead of parsing notes itself, and the download carries grubber v0.18.0 beside the engine, so there is nothing to install. The core lifecycle commands run without it; for a source build, make grubber fetches it.
repair and refresh exit non-zero while something needs you. Both exited 0 with records left unresolved, broken bookmarks or failed metadata writes, so neither could drive a monitor. repair exits 1 while a record stays unresolved or a repaired file lacks metadata (files on an unmounted volume do not count); refresh exits 1 on failed writes, broken bookmarks or missing files.
★ is not a binder name. With the tags backend a binder is a Finder tag, and ★ is the marker fileregister owns, so removing a binder named ★ stripped the marker from files still in other binders. A new binder by that name is now refused.
Thirty-six correctness fixes, from a pass over every subcommand. The ones worth knowing: a damaged or unreadable bookmarks.json is an error instead of an empty database. Every writer saves the whole map back, so the next add replaced all stored bookmarks with the few it had just made. An index that cannot be read in full stops the run. add and aka hold their locks across the uniqueness check. A rewritten file keeps its extended attributes. A Finder tag you had set before a binder of the same name is never removed. A container from elsewhere is treated as untrusted. repair takes a file only when it is sure, compares names NFC, and says when it could not write metadata. of tells engine failures, copies and same-named files apart. YAML values are quoted whenever they would not read back as themselves, annotate --prose skips every code fence, and CRLF notes read. list --help answers instead of listing; it had accepted the flag and ignored it.
Download (Apple Silicon): fileregister-macos-arm64.tar.gz bundles register with its two helpers in libexec/, the fileanchor engine and grubber, ready to run, plus each component's licence in licenses/ (register and the engine are PolyForm Noncommercial, grubber is MIT). Fetched with curl it runs as-is; after a browser download, clear the quarantine flag once: xattr -dr com.apple.quarantine register libexec. Intel Macs: build from source (go install + make fileanchor + make grubber).
License: PolyForm Noncommercial 1.0.0. (use, change, non-commercial)
fileregister 1.3.0
Breaking: binder names. To ensure future Linux compatibility, a new binder name may not contain a comma or a control character, may not start or end with whitespace, and is at most 255 bytes. A binder is written to files as a Finder tag or a kMDItemProjects entry, and the fileanchor engine now accepts only values every platform can store. add, rename (the new name), write and unmarshal check the name before anything is written. Existing binders keep working, and one with a comma can be renamed away.
Engine: fileanchor 1.1.0. Adding or removing a Finder tag no longer resets the colors of the file's other tags. Until now, setting the ★ marker did exactly that. A missing file is now reported as an error instead of as a file without metadata.
Download (Apple Silicon): fileregister-macos-arm64.tar.gz bundles register plus the fileanchor engine, ready to run. Fetched with curl it runs as-is; after a browser download, clear the quarantine flag once: xattr -dr com.apple.quarantine register libexec/fileanchor. Intel Macs: build from source (go install + make fileanchor).
License: PolyForm Noncommercial 1.0.0. (use, change, non-commercial)
fileregister 1.2.0
New: register aka. Add or remove a record's aka handles at any time, not only when the file is first added: register aka <id|aka> --add <handle> --remove <handle>. Handles stay unique across the index. Removing a handle also cleans the record's Markdown blocks: the handle leaves their aka: list, and a hand-written block that knew the record only by that handle gets the real id. add --aka on an existing record now says when the handle was not applied instead of dropping it silently.
Album (milan view): the album page links to the other albums; Markdown attachments are rendered instead of downloaded, single newlines kept.
Download (Apple Silicon): fileregister-macos-arm64.tar.gz bundles register plus the fileanchor engine, ready to run. Fetched with curl it runs as-is; after a browser download, clear the quarantine flag once: xattr -dr com.apple.quarantine register libexec/fileanchor. Intel Macs: build from source (go install + make fileanchor).
License: PolyForm Noncommercial 1.0.0. (use, change, non-commercial)
fileregister 1.1.0
register keeps plain-text JSONL indexes of file collections with durable-id bookmarks: binders as sets on the record, non-breaking aka links, resolve/repair, portable transfer. Release is macOS only.
Download (Apple Silicon): fileregister-macos-arm64.tar.gz bundles register plus the fileanchor engine, ready to run. Fetched with curl it runs as-is; after a browser download, clear the quarantine flag once: xattr -dr com.apple.quarantine register libexec/fileanchor. Intel Macs: build from source (go install + make fileanchor).
License: PolyForm Noncommercial 1.0.0. (use, change, non-commercial)