fileregister is een command-line tool die een referentielaag over bestanden legt door gebruik te maken van permanente ID's en "binders" (virtuele collecties). In tegenstelling tot traditionele mappen, kunnen binders bestanden uit verschillende locaties groeperen zonder de fysieke structuur te wijzigen.
Kernonderdelen en werking:
- Indexering: De tool gebruikt een JSONL-index als source of truth.
- Metadata: Via Markdown-sidecars kunnen metadata (in YAML-formaat) en vrije tekst aan bestanden worden gekoppeld, wat zoekbaar is via tools als
grubber en matterbase.
- Resiliëntie: Dankzij de
fileanchor-engine (momenteel specifiek voor macOS) blijven referenties naar bestanden werken, zelfs na het hernoemen of verplaatsen van bestanden.
Belangrijkste functionaliteiten:
- Permanente links: Het toekennen van handles (
--aka) waardoor bestanden altijd via een uniek ID kunnen worden opgelost naar hun huidige pad.
- Portabiliteit: De mogelijkheid om binders te verpakken (
marshal) en op andere machines te herstellen (unmarshal).
- Visualisatie: Het genereren van statische HTML-fotoalbums op basis van de inhoud van een binder.
- macOS Integratie: Synchronisatie met Spotlight-velden, Finder-tags en xattrs.
De tool is geschreven in Go, terwijl de macOS-metadata-engine is gebouwd met Swift.
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...]
| Subcommando | Doel |
add | Registreert 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. |
promote | Schrijft het Markdown-blok per binder voor de records; --edit opent de notitie in de editor. |
annotate | Bewerkt velden of tekst van een bestaand blok via de command line (--set, --unset, --prose). |
remove | Verwijdert bestanden uit een binder; als de binder-set leeg wordt, blijft het record als bookmark bestaan. |
refresh | Pusht de record-status naar macOS-metadata. |
audit | Genereert een read-only consistentierapport in beide richtingen. |
repair | Herstelt een gebroken bookmark van een verplaatst bestand via Spotlight. |
rename | Hernoemt een binder in alle records en xattrs; --merge is nodig bij een bestaande naam. |
cleanup | Reviewt drift tussen lagen (verouderde blokken, niet-geïndexeerde annotaties) en laat de gebruiker beslissen per item. |
write | Leest JSONL van stdin en schrijft referentierecords naar Markdown of JSONL. |
list | Toont alle binders met aantallen, of de bestanden in één specifieke binder; --inbox/--curated filtert op annotatiestatus, --paths en --json voor piping. |
resolve | Zet een ID of aka-handle om in een pad; --record print het volledige record. |
of | Rapporteert het ID, de aka en de binders van een opgegeven bestand. |
marshal | Verpakt de bestanden, notities en het manifest van een binder in een portable tar.gz. |
unmarshal | Pakt een container uit, spiegelt bestanden naar hun oorsprong en recreëert records. Idempotent; conflicten worden geparkeerd. Origins buiten collections/ vereisen --scatter. |
reindex | Herbouwt de index vanuit Markdown referentieblokken; --dry-run voor preview. |
order | Arrangeert een binder voor presentatie (set/show/move). |
album | Rendert 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:
$FILEANCHOR — expliciet pad.
fileanchor in je PATH — eigen build of systeeminstallatie.
<bindir>/libexec/fileanchor — geplaatst via make install.
Twee lagen
- De JSONL-index: Deze is leidend. Elke
register add schrijft hiernaar.
- 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.
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...]
| Subcommando | Doel |
add | Registreert 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. |
promote | Schrijft het Markdown-blok per binder voor de records; --edit opent de notitie in de editor. |
annotate | Bewerkt velden of tekst van een bestaand blok via de command line (--set, --unset, --prose). |
remove | Verwijdert bestanden uit een binder; als de binder-set leeg wordt, blijft het record als bookmark bestaan. |
refresh | Pusht de record-status naar macOS-metadata. |
audit | Genereert een read-only consistentierapport in beide richtingen. |
repair | Herstelt een gebroken bookmark van een verplaatst bestand via Spotlight. |
rename | Hernoemt een binder in alle records en xattrs; --merge is nodig bij een bestaande naam. |
cleanup | Reviewt drift tussen lagen (verouderde blokken, niet-geïndexeerde annotaties) en laat de gebruiker beslissen per item. |
write | Leest JSONL van stdin en schrijft referentierecords naar Markdown of JSONL. |
list | Toont alle binders met aantallen, of de bestanden in één specifieke binder; --inbox/--curated filtert op annotatiestatus, --paths en --json voor piping. |
resolve | Zet een ID of aka-handle om in een pad; --record print het volledige record. |
of | Rapporteert het ID, de aka en de binders van een opgegeven bestand. |
marshal | Verpakt de bestanden, notities en het manifest van een binder in een portable tar.gz. |
unmarshal | Pakt een container uit, spiegelt bestanden naar hun oorsprong en recreëert records. Idempotent; conflicten worden geparkeerd. Origins buiten collections/ vereisen --scatter. |
reindex | Herbouwt de index vanuit Markdown referentieblokken; --dry-run voor preview. |
order | Arrangeert een binder voor presentatie (set/show/move). |
album | Rendert 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:
$FILEANCHOR — expliciet pad.
fileanchor in je PATH — eigen build of systeeminstallatie.
<bindir>/libexec/fileanchor — geplaatst via make install.
Twee lagen
- De JSONL-index: Deze is leidend. Elke
register add schrijft hiernaar.
- 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.