fileregister: Permanente ID's en zelfdocumenterende binders voor bestanden

Wat het doet

De tool register schrijft een record voor elk bestand dat je aanlevert: een permanent ID, de binders waartoe het bestand behoort en eventuele extra velden die je toevoegt. Deze records worden opgeslagen in een JSONL-index naast je notities; deze is leesbaar met cat, doorzoekbaar met grep en kan worden beheerd met git. De index is de source of truth.

Elk record kan een Markdown-sidecar bevatten: een notitie per bestand waarin harde feiten als YAML-velden worden bewaard (zoals een bedrag, betalingsdatum, leverancier of bijschrift), met daarnaast vrije tekst voor alles wat geen veld is. De velden worden gebruikt voor queries via grubber en matterbase, terwijl de tekst bedoeld is voor de gebruiker. Dit transformeert een eenvoudige set bestanden in een zelfdocumenterende binder: een werkboek voor een project, een fotoalbum of een collectie die zichzelf uitlegt.

Alle informatie die direct op het bestand zelf wordt geschreven (het ID in de xattr, een macOS-bookmark, Finder-tags, Spotlight-velden) is een cache die is afgeleid van de index. Dit zorgt ervoor dat een referentie blijft werken als het bestand wordt hernoemd, naar een andere schijf wordt verplaatst of wordt gekopieerd naar een tweede Mac. Met register refresh kan dit worden herbouwd vanuit de index wanneer de cache afwijkt of na een kopieeractie waarbij xattrs verloren zijn gegaan.

register zelf is geschreven in portable Go; de OS-specifieke taken worden afgehandeld door de fileanchor-engine, die momenteel is gebouwd voor macOS. Voor gebruik op Linux is een Linux-versie van fileanchor de enige ontbrekende schakel.

Een eerste sessie

export GRUBBER_NOTES=~/notes         # waar de index en notities staan
register add ~/scans/scan_0043.pdf --binder insurance --aka car-policy
register list insurance
register resolve car-policy           # print het pad, ongeacht de huidige naam
open "$(register resolve car-policy)"

In dit voorbeeld is het document gescand onder een tijdelijke naam; --aka car-policy geeft het een handle die makkelijker te onthouden is. Zelfs als het bestand zes maanden later policy-2026.pdf heet en op een NAS staat, zal register resolve car-policy nog steeds het juiste pad printen. Omgekeerd zal register of /Volumes/nas/policy-2026.pdf het ID van het bestand lezen en rapporteren in welke binders het zich bevindt.

Functionaliteiten

Documenten verzamelen voor een project

Een binder is een set in het record, geen fysieke map. Het contract, twee scans en een spreadsheet kunnen in verschillende mappen staan, maar toch één werkset vormen. Het toevoegen van een bestand aan een binder verplaatst het bestand niet, en één bestand kan in meerdere binders tegelijk zitten.

  • register list: toont alle binders met aantallen.
  • register list <binder>: toont de leden.
  • --paths: geeft absolute paden voor gebruik in andere tools.

Data koppelen aan een bestand

Met register promote wordt een Markdown-notitie geschreven met één YAML-blok per bestand. Hierin kun je velden invullen (bedrag, datum, leverancier, bijschrift) en vrije tekst toevoegen. Een bestand kan in verschillende binders verschillende velden hebben. Met register annotate kunnen deze wijzigingen via een script of GUI worden doorgevoerd zonder de notitie handmatig te openen.

Permanente links naar bestanden

Net als Hookmark, maar in platte tekst in plaats van een database. De --aka optie geeft een record een handle die losstaat van de bestandsnaam. register resolve <handle> zet dit om in een pad, bijvoorbeeld achter een milan:// URL, in een Shortcut of in een shell-alias. Omdat de lookup via het record gaat, overleven links het hernoemen en verplaatsen van bestanden.

Reverse lookup

Met register of <file> kun je bepalen wat een bestand is en waar het deel van uitmaakt, gebaseerd op het ID op het bestand.

Binders ordenen

Een binder blijft een ongeordende set; de volgorde wordt bepaald door sort-sleutels in de notitie, die bewerkt kunnen worden met register order move. Zie ORDERING.md voor details.

Binders renderen als fotoalbum

Met register album <binder> --open wordt een statische HTML-map gegenereerd met miniaturen, bijschriften en een kaart per afbeelding, zonder JavaScript. Bijschriften zijn simpelweg velden in de notitie. Met --milan kan het album op het lokale netwerk (LAN) worden gepubliceerd. Zie ALBUM.md.

Binders herbouwen op een andere machine

Met register marshal worden bestanden, notities en een manifest verpakt in een tar.gz. Met register unmarshal wordt dit op een andere machine uitgepakt, waarbij bestanden naar hun oorspronkelijke paden worden gespiegeld en records worden gerecreëerd. Mirroring naar paden buiten collections/ is optioneel (--scatter) om te voorkomen dat externe containers willekeurig over het systeem schrijven. Het containerformaat is OS-neutraal.

macOS-synchronisatie

  • register refresh: pusht de status van het record terug naar tags, Spotlight-velden en xattrs.
  • register audit: rapporteert inconsistenties in beide richtingen.
  • register repair: herstelt gebroken bookmarks van verplaatste bestanden via Spotlight.
  • register cleanup: begeleidt de gebruiker bij beslissingen over conflicten.

Geen van deze commando's verwijdert records automatisch.

Querying

De index is JSONL en de notities zijn YAML in Markdown. Hierdoor kan grubber beide doorzoeken en biedt matterbase een tabelweergave en query-builder. Zie WORKFLOWS.md.

(Voor de vraag waarom dit nodig is terwijl macOS al tags heeft, zie RATIONALE.md. Kort gezegd: fileregister gebruikt tags en kan ze herbouwen.)

Opdrachten

register <subcommand> [args...]

SubcommandoDoel
addRegistreert bestanden in de index (bookmark + xattr + record). Met --binder voegt het bestand zich bij die binder; zonder binder wordt het een bookmark (permanent ID + optionele aka). --md schrijft ook een annotatienotitie.
promoteSchrijft het Markdown-blok per binder voor de records; --edit opent de notitie in de editor.
annotateBewerkt velden of tekst van een bestaand blok via de command line (--set, --unset, --prose).
removeVerwijdert bestanden uit een binder; als de binder-set leeg wordt, blijft het record als bookmark bestaan.
refreshPusht de record-status naar macOS-metadata.
auditGenereert een read-only consistentierapport in beide richtingen.
repairHerstelt een gebroken bookmark van een verplaatst bestand via Spotlight.
renameHernoemt een binder in alle records en xattrs; --merge is nodig bij een bestaande naam.
cleanupReviewt drift tussen lagen (verouderde blokken, niet-geïndexeerde annotaties) en laat de gebruiker beslissen per item.
writeLeest JSONL van stdin en schrijft referentierecords naar Markdown of JSONL.
listToont alle binders met aantallen, of de bestanden in één specifieke binder; --inbox/--curated filtert op annotatiestatus, --paths en --json voor piping.
resolveZet een ID of aka-handle om in een pad; --record print het volledige record.
ofRapporteert het ID, de aka en de binders van een opgegeven bestand.
marshalVerpakt de bestanden, notities en het manifest van een binder in een portable tar.gz.
unmarshalPakt een container uit, spiegelt bestanden naar hun oorsprong en recreëert records. Idempotent; conflicten worden geparkeerd. Origins buiten collections/ vereisen --scatter.
reindexHerbouwt de index vanuit Markdown referentieblokken; --dry-run voor preview.
orderArrangeert een binder voor presentatie (set/show/move).
albumRendert een binder als een statisch HTML-album; --milan publiceert dit op het LAN.

Meer voorbeelden

# Een sessie-binder instellen, zodat --binder hierna weggelaten kan worden
export REGISTER_BINDER=project-alpha

register add document.pdf --kind pdf
register add ~/scans/*.pdf --kind pdf        # batch: één bookmark write, één append
register add document.pdf --aka alpha-brief  # geen binder: een bookmark met handle
register add document.pdf --md               # schrijft de annotatienotitie
register promote                             # blokken voor de hele binder
register promote --id 482910337              # of voor slechts één record
register annotate project-alpha alpha-brief --set amount=142.50 --set status=paid
register list --inbox                        # binders met records die nog niet geannoteerd zijn
register list project-alpha --paths
register order move project-alpha 482910337 --after 482910901
register album project-alpha --open
register marshal --binder project-alpha --out project-alpha.tar.gz
register unmarshal project-alpha.tar.gz      # op de andere machine
register refresh --dry-run
register audit --binder project-alpha
register repair --interactive
register reindex --dry-run

Installatie

Als fileanchor al in je PATH staat: go install github.com/rhsev/fileregister/cmd/register@latest

Anders beide bouwen vanuit een checkout:

make fileanchor        # de metadata engine (vereist Swift toolchain)
make install           # standaard naar ~/bin
make install PREFIX=/usr/local/bin

Vereisten: Go en macOS (voor de huidige fileanchor build). register is een zelfstandig Go-binair bestand; elk subcommando is native. De CLI heeft zelf geen koppeling met macOS; dat zit in de fileanchor engine. Een Linux-port is dus een port van fileanchor, niet van register.

Bijbehorende releases

register start de fileanchor engine (rhsev/fileanchor) voor elke metadata-operatie. Een werkende fileanchor is dus vereist. De query-tool grubber (rhsev/grubber) is optioneel: de register commando's werken zonder, maar de Markdown-sidecar laag is pas echt nuttig met grubber voor het queryen van velden.

Configuratie

Stel de directory voor je notities in: export GRUBBER_NOTES=~/notes

Of gebruik een grubber config set (heeft prioriteit): export GRUBBER_SET=contracts (veld in ~/.config/grubber/config.yaml)

Optioneel:

  • export REGISTER_BINDER=berlin-2024 (standaard binder voor add/remove/promote)
  • export GRUBBERCONFIG=~/path/to/config.yaml (alleen om GRUBBERSET op te lossen)
  • export FILEANCHOR=/path/to/fileanchor

De metadata-engine

Alle macOS-metadata werk verloopt via fileanchor, een native engine die move-resiliente bookmarks, Finder-tags, Spotlight-queries en xattrs beschikbaar stelt via één batch stdio protocol. Het draait één keer per commando en verwerkt de hele batch in-process om overhead bij het opstarten van processen per bestand te voorkomen.

Er wordt geen binair bestand meegeleverd in deze repo. make fileanchor kloont fileanchor op een gepinde tag en bouwt deze met SwiftPM. Voor het bouwen is een Swift toolchain (Xcode of Command Line Tools) nodig; het produceert een arm64-binair bestand voor macOS 13 of later.

Resolutievolgorde voor fileanchor:

  1. $FILEANCHOR — expliciet pad.
  2. fileanchor in je PATH — eigen build of systeeminstallatie.
  3. <bindir>/libexec/fileanchor — geplaatst via make install.

Twee lagen

  1. De JSONL-index: Deze is leidend. Elke register add schrijft hiernaar.
  2. Markdown-notities: Een optionele annotatielaag. register promote voegt een blok toe dat via een ID is gekoppeld.

Een record zonder annotatie is normaal (zie register list --inbox). Een record waarvan de binder-set leeg is, is een bookmark: een bestand dat enkel op basis van identiteit wordt gevolgd en niet in een binder zit. Bookmarks zijn first-class burgers en worden nooit automatisch verwijderd.

Documentatie

  • SPEC.md — on-disk formaat, datamodel, ontwerpbeslissingen.
  • WORKFLOWS.md — organiseren en queryen van collecties.
  • ORDERING.md — sort-sleutels en register order.
  • ALBUM.md — statische fotoalbums en LAN-serving.
  • RATIONALE.md — waarom dit bestaat ondanks macOS-tags.

Licentie

PolyForm Noncommercial 1.0.0 — source-available, geen OSI open source. Vrij om te lezen, gebruiken en op voort te bouwen voor alles wat niet-commercieel is.