Op mijn blog schrijf ik meestal over Microsoft 365, SharePoint en Copilot. Toch past dit onderwerp daar prima naast. AI wordt pas interessant als het een praktisch probleem oplost, en dit is er zo een: sneller notities verwerken zonder dat mijn Obsidian vault rommelig wordt.
Een Obsidian vault blijft alleen bruikbaar als nieuwe notities snel op de juiste plek terechtkomen. Dat klinkt eenvoudig, totdat je dagelijks losse snippets, clipboard-notities, downloads en halve ideeën verzamelt. Voor je het weet staat je inbox vol met bestanden als Untitled 1.md, 2026-05-19.md en reminders.md.
Ik wilde dat proces automatiseren, maar wel voorzichtig. Een automation mag helpen met opruimen, niet ineens mijn hele vault herschrijven.
De oplossing werd een combinatie van Hazel en Hermes:
- Hazel kijkt of er een nieuw bestand binnenkomt.
- Een shellscript doet de veiligheidschecks.
- Hermes leest de notitie, verbetert die voorzichtig en verplaatst hem naar de juiste PARA-map in Obsidian.

Het probleem
Mijn Obsidian vault gebruikt PARA:
02 Projectsvoor actief werk met een concreet resultaat.03 Areasvoor doorlopende verantwoordelijkheden.04 Resourcesvoor kennis, snippets, cheat sheets en referentie.05 Archivevoor afgeronde of oude notities.
Nieuwe notities komen op twee manieren binnen:
- bewust via
01 Inbox, mijn verwerkingsqueue; - onbewust direct in de root van de vault, bijvoorbeeld via clipboard-acties, snelle Obsidian-captures of tekstsnippets vanuit PopClip.
Die tweede stroom gebruik ik veel. Ik selecteer regelmatig een stuk tekst op een webpagina, in documentatie of in een artikel. Met een PopClip-extensie stuur ik die selectie direct naar Obsidian. Dat werkt lekker snel, maar die snippets komen automatisch in de hoofdmap van mijn vault terecht. Ze hebben dan nog geen duidelijke titel, tags of plek binnen PARA.

Die tweede categorie is handig, maar ook gevaarlijk. Als je de root van je vault laat monitoren, kan een automation bij de eerste run ook bestaande bestanden oppakken. Dat wil je niet.
Hazel als simpele trigger
Hazel is goed in één ding: reageren op bestanden in een map. Dat maakt het een prima trigger.
De inhoudelijke beslissing laat ik niet aan Hazel over. Hazel hoeft niet te weten of een notitie een project, resource of archive-item is. Hazel hoeft alleen het script te starten en het bestand mee te geven.
De regel is bewust simpel gehouden:
- monitor
01 Inboxvoor nieuwe notities; - monitor de root van de vault alleen voor directe nieuwe
.md-bestanden; - verwerk niet recursief door alle PARA-mappen heen.

Tip: Laat Hazel zo weinig mogelijk beslissen. Gebruik Hazel als deurbel, niet als redacteur.
Het script als veiligheidslaag
Tussen Hazel en Hermes staat een shellscript. Dat script doet de saaie, maar belangrijke controles:
- bestaat het bestand nog?
- is het geen tijdelijk macOS- of iCloud-bestand?
- staat het bestand in
01 Inboxof direct in de root van de vault? - is er al een andere triage-run bezig?
- is het bestand stabiel, of wordt het nog gesynchroniseerd?
Daarna pas wordt Hermes gestart.
De belangrijkste bescherming zit op de root van de vault. Die root is alleen bedoeld voor nieuwe clipboard-notities. Daarom worden root-bestanden ouder dan 10 minuten overgeslagen.

Dat voorkomt dat Hazel bij het activeren van een nieuwe regel ineens oude bestanden zoals CLAUDE.md, reminders.md of oude dagnotities door Hermes laat verwerken.
Hermes als Obsidian PARA-agent
Hermes krijgt een gerichte opdracht:
- inspecteer het bestand;
- behoud de originele taal van de notitie;
- vertaal clipboard-content niet;
- voeg waar nuttig YAML frontmatter toe;
- verbeter koppen en leesbaarheid voorzichtig;
- voeg tags en aliases toe;
- verplaats de notitie naar de juiste bestaande PARA-map;
- maak geen nieuwe mappen tenzij dat echt nodig is.
Dat laatste is belangrijk. Een automatisering die zelf allerlei nieuwe mappen maakt, zorgt vaak voor meer rommel dan je eerst had.

Voor tekstbestanden mag Hermes de inhoud verbeteren. Voor binary bestanden, zoals PDF’s of afbeeldingen, blijft het origineel behouden. Eventueel kan Hermes er een companion Markdown-notitie naast zetten met metadata of een korte samenvatting.
Logging maakt het verschil
Omdat Hazel zelf weinig zicht geeft, schrijft het script alles naar een eigen logbestand:
/Users/pkops/.hermes/logs/obsidian-para-triage.log
Daarin staat bijvoorbeeld:
Triggered for: .../The Vault/Untitled 1.md
Starting Hermes triage...
Done: .../The Vault/Untitled 1.md
SKIP: Root-level file is older than 10 minutes
Dat is genoeg om te zien of Hazel triggert, of Hermes start en waarom een bestand eventueel wordt overgeslagen.
Waarom deze aanpak prettig werkt
Deze setup verdeelt de verantwoordelijkheden netjes:
- Hazel kijkt naar bestandswijzigingen.
- Het script bewaakt de grenzen.
- Hermes doet het denkwerk.
- Obsidian blijft gewoon Markdown op schijf.
Dat maakt de oplossing ook goed te testen. Als er iets misgaat, kun je in de log zien waar het stopt. En omdat het script alleen 01 Inbox en recente root-bestanden accepteert, blijft de rest van de vault buiten schot.
Praktische tips als je dit zelf bouwt
Gebruik een aparte inbox. Laat niet je hele vault recursief monitoren.
Begin met logging voordat je AI toevoegt. Als je niet kunt zien wat Hazel doorgeeft, wordt debuggen lastig.
Zet een lock in je script. Hazel kan meerdere bestanden kort na elkaar aanbieden. Zonder lock start je misschien meerdere agent-runs tegelijk.
Laat de automation oude root-bestanden negeren. De root van een vault bevat vaak historische restjes, configuratiebestanden of snelle notities die je niet automatisch wilt laten aanpassen.
Bewaar de originele taal van notities. Zeker bij clipboard-content wil je meestal opschonen en structureren, niet vertalen.
Het script
Voor de volledigheid is dit de kern van het script. In mijn eigen versie staan natuurlijk de echte paden naar Hermes, de vault en het logbestand. Als je dit zelf gebruikt, pas vooral die variabelen bovenaan aan.
Het belangrijkste zit niet in de Hermes-aanroep zelf, maar in de controles ervoor: alleen bestanden uit 01 Inbox of recente root-bestanden worden verwerkt, tijdelijke bestanden worden overgeslagen en een lock voorkomt dat meerdere runs tegelijk starten.
<details>
<summary>Voorbeeldscript voor Hazel en Hermes</summary>
<pre class="wp-block-code"><code>#!/bin/bash
set -euo pipefail
# Hazel -> Hermes Obsidian PARA triage
# Usage from Hazel: /path/to/obsidian-para-triage.sh "$1"
HERMES="/path/to/hermes"
VAULT="/path/to/Obsidian/The Vault"
INBOX="$VAULT/01 Inbox"
LOG_DIR="$HOME/.hermes/logs"
LOG="$LOG_DIR/obsidian-para-triage.log"
LOCK_DIR="/tmp/obsidian-para-triage.lock"
mkdir -p "$LOG_DIR"
log() {
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" >> "$LOG"
}
if [[ $# -lt 1 ]]; then
log "ERROR: No file argument supplied."
exit 64
fi
FILE="$1"
# Avoid parallel Hermes runs when Hazel matches multiple files at once.
if ! mkdir "$LOCK_DIR" 2>/dev/null; then
log "Another triage run is active; waiting for lock..."
while ! mkdir "$LOCK_DIR" 2>/dev/null; do
sleep 2
done
fi
trap 'rmdir "$LOCK_DIR" 2>/dev/null || true' EXIT
log "Triggered for: $FILE"
if [[ ! -e "$FILE" ]]; then
log "SKIP: File does not exist anymore: $FILE"
exit 0
fi
BASENAME="$(basename "$FILE")"
# Skip macOS, Hazel and iCloud temporary files.
case "$BASENAME" in
.*|*.tmp|*.download|*.icloud|~*)
log "SKIP: Temporary or hidden file: $BASENAME"
exit 0
;;
esac
if [[ -d "$FILE" ]]; then
log "SKIP: Directories are not processed: $FILE"
exit 0
fi
PARENT_DIR="$(dirname "$FILE")"
case "$FILE" in
"$INBOX"/*) ;;
*)
if [[ "$PARENT_DIR" != "$VAULT" ]]; then
log "SKIP: File is outside triage inbox and not a direct vault-root file: $FILE"
exit 0
fi
# Root monitoring is only for newly-created clipboard or PopClip notes.
# Skip older root files to avoid processing historical notes.
now_epoch="$(date +%s)"
file_mtime="$(stat -f%m "$FILE" 2>/dev/null || echo 0)"
age_seconds=$((now_epoch - file_mtime))
if [[ "$age_seconds" -gt 600 ]]; then
log "SKIP: Root-level file is older than 10 minutes (${age_seconds}s): $FILE"
exit 0
fi
;;
esac
# Wait until file size is stable, useful for iCloud sync and larger files.
last_size=-1
stable_count=0
for i in {1..30}; do
if [[ ! -e "$FILE" ]]; then
log "SKIP: File disappeared while waiting: $FILE"
exit 0
fi
size=$(stat -f%z "$FILE" 2>/dev/null || echo -1)
if [[ "$size" == "$last_size" && "$size" != "-1" ]]; then
stable_count=$((stable_count + 1))
else
stable_count=0
last_size="$size"
fi
if [[ "$stable_count" -ge 2 ]]; then
break
fi
sleep 2
done
PROMPT_FILE="$(mktemp /tmp/obsidian-para-triage-prompt.XXXXXX.txt)"
trap 'rm -f "$PROMPT_FILE"; rmdir "$LOCK_DIR" 2>/dev/null || true' EXIT
cat > "$PROMPT_FILE" <<PROMPT
You are an Obsidian PARA triage agent.
Vault path:
$VAULT
Inbox folder:
$INBOX
New file to process:
$FILE
Important language rule:
- Preserve the original language of the document.
- Do not translate clipboard captures or pasted content.
- Only correct grammar, spelling and style in the existing language when useful.
Task:
1. Inspect the file.
2. Decide whether it belongs in Projects, Areas, Resources or Archive.
3. If it is Markdown or plain text, improve it conservatively.
4. Add useful YAML frontmatter, tags and aliases.
5. Move the file out of the inbox or vault root into the right PARA folder.
6. Avoid duplicates and choose a safe filename when needed.
PROMPT
log "Starting Hermes triage..."
set +e
"$HERMES" chat \
--source hazel-obsidian-para-triage \
--skills obsidian \
--toolsets file,terminal,skills \
-q "$(cat "$PROMPT_FILE")" >> "$LOG" 2>&1
status=$?
set -e
if [[ $status -ne 0 ]]; then
log "ERROR: Hermes triage failed with exit code $status"
exit $status
fi
log "Done: $FILE"</code></pre>
</details>
Conclusie
Deze automatisering is geen grote AI-workflow. Het is vooral een praktische opruimhulp.
Hazel ziet dat er iets nieuws is. Hermes kijkt wat het is. Het script zorgt dat de automation binnen de lijntjes blijft. Daardoor blijft de Obsidian vault bruikbaar zonder dat elke snelle notitie handmatig verwerkt hoeft te worden.
Dat is precies waar dit soort automatisering goed in is: klein beginnen, duidelijke grenzen instellen en pas daarna slimmer maken.


Wees de eerste om te reageren