Was macht obs-f?
obs-f ist ein Kommandozeilen-Tool, das du im Terminal tippst. Es macht 5 Dinge nacheinander:
Gesamtfluss als Diagramm
flowchart TD
A["obs-f im Terminal tippen"] --> B["Rezept-Menue (FZF)"]
B --> C{"Welcher Modus?"}
C -->|"HEUTE/WOCHE/BATCH"| D["_obs_f_collect\nDateien sammeln"]
C -->|"EINZELN"| E["_obs_f_pick_file\nDatei waehlen"]
C -->|"__CMD__"| F["Shell-Befehl\nausfuehren"]
D --> G["_obs_f_pick_fabric_pattern\nPattern-Menue (FZF)"]
E --> G
G --> H["Fabric AI\nAnalyse auf Deutsch"]
H --> I["Output im Terminal\nanzeigen"]
I --> J{"Weiter mit\nClaude Code?"}
J -->|"j"| K["_obs_f_claude_handoff\nKontext-Datei schreiben\nClaude Code starten"]
J -->|"N"| L["Fertig"]
Abb. 1: Gesamtfluss — Vom Terminal-Aufruf zum Ergebnis
Grundlagen für Anfänger
Was ist eine Shell-Funktion?
Eine Shell-Funktion ist ein wiederverwendbarer Code-Block in deinem Terminal. Statt lange Befehle zu tippen, gibst du nur den Funktionsnamen ein:
# Definition (in deiner .zshrc oder einer extra Datei)
meine_funktion() {
echo "Hallo Welt"
}
# Aufruf
meine_funktion
# Ausgabe: Hallo Welt
Funktionen, die mit _ beginnen (z.B. _obs_f_run), sind Helper – sie werden nicht direkt aufgerufen, sondern von anderen Funktionen benutzt.
Was ist FZF?
FZF (Fuzzy Finder) ist ein Terminal-Tool, das interaktive Auswahl-Menues erzeugt. Du kennst Dropdown-Menues aus Websites – FZF ist das Gleiche, aber im Terminal.
# Installation
brew install fzf
# Einfachstes Beispiel: Datei waehlen
ls | fzf
# Mit Preview (zeigt Dateiinhalt rechts)
ls | fzf --preview="cat {}" --preview-window=right:50%
Wichtige FZF-Flags, die obs-f nutzt:
| Flag | Was es tut | Beispiel |
|---|---|---|
--prompt | Text vor dem Suchfeld | --prompt="waehle > " |
--header | Ueberschrift oben im Menue | --header="Fabric Patterns" |
--preview | Shell-Befehl, der rechts ausgefuehrt wird | --preview="cat {}" |
--preview-window | Wo/wie gross die Preview ist | --preview-window=right:50%:wrap |
--height | Wie viel Terminal-Hoehe FZF nutzt | --height=80% |
--border | Rahmen um das Menue | --border=rounded |
--no-multi | Nur 1 Auswahl erlaubt | --no-multi |
--reverse | Liste von oben nach unten | --reverse |
--ansi | Farbcodes in der Liste erlauben | --ansi |
--delimiter | Trennzeichen fuer Spalten | --delimiter='|' |
--with-nth | Nur bestimmte Spalten anzeigen | --with-nth=2 |
--no-info | Keine Zaehler-Zeile unten | --no-info |
Was ist Fabric?
Fabric ist ein CLI-Tool von Daniel Miessler. Es hat ueber 200 vordefinierte AI-Analyse-Patterns. Jedes Pattern ist ein Ordner mit einer system.md Datei – einem System-Prompt.
# Installation
go install github.com/danielmiessler/fabric@latest
# oder auf macOS:
brew install fabric-ai
# Einfachstes Beispiel: Text zusammenfassen
echo "Langer Text..." | fabric -p summarize
# Pattern-Liste anzeigen
ls ~/.config/fabric/patterns/
Wie ein Pattern aufgebaut ist:
~/.config/fabric/patterns/
extract_wisdom/
system.md ← Das ist der System-Prompt
summarize/
system.md
analyze_prose/
system.md
... (239 weitere)
Die system.md enthaelt Anweisungen fuer die AI, z.B.:
# IDENTITY and PURPOSE
You are a wisdom extraction service...
# STEPS
1. Extract surprising insights
2. Find the most important ideas
...
# OUTPUT FORMAT
- Use markdown
- Section: IDEAS, INSIGHTS, QUOTES...
Was ist ein Heredoc?
Ein Heredoc (<<EOF ... EOF) schreibt mehrzeiligen Text in eine Datei oder Variable. obs-f nutzt es fuer die Kontext-Datei:
cat > datei.md <<EOF
# Ueberschrift
Inhalt mit $variablen die ersetzt werden.
EOF
Was ist eine Pipe?
Die Pipe (|) schickt die Ausgabe eines Befehls als Eingabe an den naechsten:
# Dateien sammeln -> an Fabric schicken
cat datei1.md datei2.md | fabric -p summarize
# ^ Output ^ wird hier Input
Was ist Obsidian CLI?
Obsidian CLI ist eine Kommandozeilen-Schnittstelle, die ab Obsidian v1.12 verfuegbar ist. Sie erlaubt dir, JavaScript direkt in Obsidians Metadata Cache auszufuehren – also Dateien, Tags und Frontmatter abzufragen, ohne das Dateisystem direkt durchsuchen zu muessen.
Warum ist das wichtig fuer obs-f? Obsidian hat einen internen Cache aller Dateien mit Metadaten (Tags, Frontmatter, Aenderungsdatum). Ueber die CLI kann obs-f diesen Cache in Millisekunden abfragen, statt tausende Dateien per find zu durchsuchen.
Installation
Voraussetzung: Obsidian v1.12 oder neuer.
macOS (einmalig):
# Obsidian-Binary zum PATH hinzufuegen
echo 'export PATH="/Applications/Obsidian.app/Contents/MacOS:$PATH"' >> ~/.zprofile
# Terminal neu starten oder:
source ~/.zprofile
# Testen
obsidian --version
Linux:
# AppImage: Obsidian binary ist im AppImage enthalten
# Flatpak: flatpak run md.obsidian.Obsidian --help
echo 'alias obsidian="/pfad/zu/obsidian"' >> ~/.bashrc
Wie obs-f die CLI nutzt
obs-f verwendet den eval-Befehl, um JavaScript in Obsidian auszufuehren:
# Grundsyntax
obsidian eval --vault "MeinVault" --code 'JavaScript-Code'
# Beispiel: Alle heutigen Markdown-Dateien auflisten
obsidian eval --vault "Akademie" --code 'JSON.stringify(
app.vault.getFiles()
.filter(f => f.extension === "md" && f.stat.mtime > Date.now() - 86400000)
.map(f => f.path)
)'
Wichtige Objekte im eval-Kontext:
| Objekt | Zugriff auf | Beispiel |
|---|---|---|
app.vault | Alle Dateien im Vault | app.vault.getFiles() |
app.metadataCache | Tags, Frontmatter, Links | app.metadataCache.getTags() |
f.stat.mtime | Aenderungszeitpunkt (Unix-ms) | f.stat.mtime > 1708300800000 |
f.extension | Dateiendung | f.extension === 'md' |
f.path | Relativer Pfad im Vault | f.path.includes('Marketing') |
Der _obs_eval Helper:
_obs_eval() {
local vault="$1" code="$2"
obsidian eval --vault "$(basename "$vault")" --code "$code" 2>/dev/null
}
Wenn Obsidian CLI nicht verfuegbar ist, faellt obs-f automatisch auf Filesystem-Suche mit find zurueck (siehe Funktion 2).
Obsidian CLI Diagramm
flowchart LR
A["obs-f Funktion"] --> B["_obs_eval Helper"]
B --> C["obsidian eval --vault --code"]
C --> D["Obsidian Metadata Cache"]
D --> E["JSON-Array mit Dateipfaden"]
E --> F["obs-f verarbeitet Ergebnis"]
style D fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
Abb. 2: Obsidian CLI — Vom Funktionsaufruf zum Metadata Cache
Alle Shell-Funktionen im Überblick
obs-f besteht aus 8 Funktionen. Hier ist die Aufruf-Hierarchie:
Funktions-Hierarchie als Diagramm
flowchart TD
OBS["obs-f\nHauptfunktion"] --> TAG["_obs_f_pick_tag\nTag/Ordner-Filter"]
OBS --> SINGLE["_obs_f_single\nEinzeldatei-Modus"]
OBS --> RUN["_obs_f_run\nBatch-Modus"]
SINGLE --> PICK["_obs_f_pick_file\nDatei waehlen"]
SINGLE --> PAT1["_obs_f_pick_fabric_pattern\nPattern waehlen"]
SINGLE --> HAND1["_obs_f_claude_handoff\nClaude Uebergabe"]
RUN --> COLL["_obs_f_collect\nDateien sammeln"]
RUN --> PAT2["_obs_f_pick_fabric_pattern\nPattern waehlen"]
RUN --> HAND2["_obs_f_claude_handoff\nClaude Uebergabe"]
COLL --> EVAL["_obs_eval\nObsidian CLI"]
style OBS fill:#4CAF50,stroke:#2E7D32,color:#fff,stroke-width:3px
style PAT1 fill:#FF9800,stroke:#E65100,color:#fff
style PAT2 fill:#FF9800,stroke:#E65100,color:#fff
style HAND1 fill:#2196F3,stroke:#0D47A1,color:#fff
style HAND2 fill:#2196F3,stroke:#0D47A1,color:#fff
Abb. 3: Funktions-Hierarchie — 8 Funktionen und ihre Abhängigkeiten
Funktion 1: obs-f – Hauptfunktion
Was sie tut: Zeigt das Rezept-Menue, parst die Auswahl und ruft den richtigen Helper auf.
Aufgerufen durch: Dich im Terminal.
Das Rezept-Array
Das Herzstuck ist ein Array aus Pipe-getrennten Strings. Jeder String ist ein Rezept:
local recipes=(
"HEUTE|Zusammenfassung|Alle heutigen Dateien zusammenfassen|today||summarize"
"HEUTE|Learnings|Key Insights von heute extrahieren|today||extract_wisdom"
"HEUTE|Nur Marketing|Heutige Marketing-Dateien|today|marketing|summarize"
"HEUTE|Nach Tag...|Tag waehlen -> heutige Dateien|today|__TAG__|summarize"
"WOCHE|Zusammenfassung|7-Tage Ueberblick|week||summarize"
"BATCH|Letzte 10|Die 10 neuesten zusammenfassen|recent||summarize|10"
"EINZELN|Datei -> Pattern|Datei waehlen, dann Pattern|__SINGLE__|||"
"CLAUDE|Heute|Claude Conversations von heute|today||summarize"
"VAULT|Conversations aufraeumen|obs-ai-digest --batch 10|__CMD__|obs-ai-digest --batch 10||"
)
Format: KATEGORIE|NAME|BESCHREIBUNG|MODUS|FILTER|PATTERN[|LIMIT]
| Feld | Bedeutung | Beispielwerte |
|---|---|---|
| KATEGORIE | Gruppe im FZF-Menue | HEUTE, WOCHE, BATCH, EINZELN, CLAUDE, VAULT |
| NAME | Anzeigename | Zusammenfassung, Learnings |
| BESCHREIBUNG | Erklaerungstext | Alle heutigen Dateien zusammenfassen |
| MODUS | Zeitfilter fuer _obs_f_collect | today, week, recent, __SINGLE__, __CMD__ |
| FILTER | Ordner- oder Tag-Filter | leer, marketing, kurse, __TAG__ |
| PATTERN | Fabric-Pattern | summarize, extract_wisdom |
| LIMIT | Max. Dateien (optional) | 10, 20 |
Spezial-Modi:
| Modus | Verhalten |
|---|---|
__SINGLE__ | Ruft _obs_f_single() auf – Einzeldatei-Modus |
__CMD__ | Fuehrt den FILTER-Wert als Shell-Befehl aus |
__TAG__ | Oeffnet _obs_f_pick_tag() zur Tag-Auswahl |
Das Display bauen
# Feste Spaltenbreiten mit printf
printf ' %-10s %-24s %s' "$cat" "$name" "$desc"
# Ergibt z.B.: " HEUTE Zusammenfassung Alle heutigen Dateien"
Kategorien werden mit Trennlinien gruppiert:
if [[ "$cat" != "$last_cat" ]]; then
display_lines+=("--- ${cat} ---")
last_cat="$cat"
fi
Rezept parsen
Nach der FZF-Auswahl wird das Rezept in seine Bestandteile zerlegt:
# Zsh parameter expansion: ${var%%|*} = alles VOR dem ersten |
# ${var#*|} = alles NACH dem ersten |
local _r="$found_recipe"
local _skip="${_r%%|*}"; _r="${_r#*|}" # CAT (uebersprungen)
_skip="${_r%%|*}"; _r="${_r#*|}" # NAME (uebersprungen)
_skip="${_r%%|*}"; _r="${_r#*|}" # DESC (uebersprungen)
local r_mode="${_r%%|*}"; _r="${_r#*|}" # today/week/recent
local r_filter="${_r%%|*}"; _r="${_r#*|}" # marketing/kurse/...
local r_pattern="${_r%%|*}" # summarize/extract_wisdom
IFS='|' read? In Zsh funktioniert IFS='|' beim Splitting anders als in Bash. Die ${var%%|*} / ${var#*|} Methode ist zuverlaessiger.
FZF Spalten-Extraktion
# printf ' %-10s %-24s %s' erzeugt feste Spalten:
# Zeichen 3-12 = Kategorie (10 Zeichen)
# Zeichen 15-38 = Name (24 Zeichen)
local sel_cat=$(echo "$selection" | cut -c3-12 | sed 's/[[:space:]]*$//')
local sel_name=$(echo "$selection" | cut -c15-38 | sed 's/[[:space:]]*$//')
Funktion 2: _obs_f_collect – Dateien sammeln
Was sie tut: Liefert Dateipfade basierend auf Zeitraum und Filter.
Aufgerufen durch: _obs_f_run()
| # | Name | Werte | Beispiel |
|---|---|---|---|
| $1 | mode | today, week, recent | today |
| $2 | filter | Ordnername oder Tag | marketing |
| $3 | limit | Max. Dateien | 10 |
| $4 | include_claude | 0/1/only | 0 |
Primaerer Weg: Obsidian CLI eval
local js_code="JSON.stringify(
app.vault.getFiles()
.filter(f =>
f.extension === 'md'
&& !f.path.includes('_Archive')
&& !f.path.includes('_templates')
&& !f.path.includes('.obsidian')
${js_claude_filter} # Conversations ein/aus
${js_time_filter} # Heute/Woche/alle
${js_path_filter} # Ordner-Filter
)
.sort((a,b) => b.stat.mtime - a.stat.mtime)
${js_limit} # .slice(0, N)
.map(f => f.path)
)"
local result=$(_obs_eval "$vault" "$js_code")
Zeitfilter (JavaScript):
case "$mode" in
today)
local today_start_ms=$(date -j -f "%Y-%m-%d %H:%M:%S" \
"$(date +%Y-%m-%d) 00:00:00" "+%s" 2>/dev/null)000
js_time_filter="&&f.stat.mtime>${today_start_ms}"
;;
week)
local week_ms=$(( $(date +%s) - 7 * 86400 ))000
js_time_filter="&&f.stat.mtime>${week_ms}"
;;
esac
Ordner-Filter (JavaScript):
case "$filter" in
marketing) js_path_filter="&&f.path.includes('20_Marketing')" ;;
kurse) js_path_filter="&&f.path.includes('10_Kurse')" ;;
wissen) js_path_filter="&&f.path.includes('30_Wissen')" ;;
strategie) js_path_filter="&&f.path.includes('50_strategie')" ;;
*)
# Tag-basierter Filter via Metadata Cache
js_path_filter="&&(()=>{
const c=app.metadataCache.getFileCache(f);
const t=c?.frontmatter?.tags;
return Array.isArray(t)
? t.some(x=>x.toLowerCase().includes('${filter}'))
: typeof t==='string' && t.includes('${filter}')
})()"
;;
esac
Fallback: Filesystem
case "$mode" in
today)
find "$vault" -name '*.md' -type f | while IFS= read -r ff; do
[[ "$(stat -f '%Sm' -t '%Y-%m-%d' "$ff")" == "$today" ]] && echo "$ff"
done
;;
week)
find "$vault" -name '*.md' -type f -mtime -7
;;
recent)
find "$vault" -name '*.md' -type f \
-exec stat -f '%m|%N' {} \; | sort -rn | head -${limit} | cut -d'|' -f2
;;
esac
Entscheidungsbaum
flowchart TD
START["_obs_f_collect aufgerufen"] --> CLI{"Obsidian CLI\nverfuegbar?"}
CLI -->|"Ja"| EVAL["_obs_eval: JavaScript\nim Metadata Cache"]
CLI -->|"Nein"| FS["Fallback:\nFilesystem mit find"]
EVAL --> MODE{"mode Parameter?"}
FS --> MODE2{"mode Parameter?"}
MODE -->|"today"| T1["mtime > heute 00:00\nals Unix-ms"]
MODE -->|"week"| W1["mtime > vor 7 Tagen\nals Unix-ms"]
MODE -->|"recent"| R1["Alle Dateien\n.slice 0 bis limit"]
MODE2 -->|"today"| T2["stat Datum == heute"]
MODE2 -->|"week"| W2["find -mtime -7"]
MODE2 -->|"recent"| R2["stat + sort + head"]
T1 --> FILTER{"filter\ngesetzt?"}
W1 --> FILTER
R1 --> FILTER
FILTER -->|"Ordner"| PATH["path.includes\nz.B. 20_Marketing"]
FILTER -->|"Tag"| META["metadataCache\nfrontmatter.tags"]
FILTER -->|"Leer"| ALL["Alle passenden\nDateien"]
PATH --> OUT["JSON-Array\nmit Pfaden"]
META --> OUT
ALL --> OUT
style EVAL fill:#4CAF50,stroke:#2E7D32,color:#fff
style FS fill:#FF9800,stroke:#E65100,color:#fff
Abb. 4: Entscheidungsbaum — Obsidian CLI vs. Filesystem Fallback
Funktion 3: _obs_f_pick_fabric_pattern – Pattern wählen
Was sie tut: Zeigt ein FZF-Menue mit 28 kuratierten Fabric-Patterns in 7 Kategorien.
Gibt zurueck: Den Pattern-Namen als String (z.B. extract_wisdom)
Vollstaendiger Code
_obs_f_pick_fabric_pattern() {
local PATTERNS_DIR="$HOME/.config/fabric/patterns"
local -a CURATED=(
"-- ANALYSIEREN & ERKLAEREN ---|"
"extract_wisdom | Weisheit, Ideen, Zitate extrahieren"
"extract_insights | Die 10 ueberraschendsten Kernerkenntnisse"
"analyze_prose | Schreibqualitaet bewerten"
"analyze_claims | Behauptungen pruefen (A-F Rating)"
"analyze_paper | Wissenschaftliche Rigor-Analyse"
"analyze_presentation | Praesentation kritisch bewerten"
"analyze_tech_impact | Technologie-Impact analysieren"
"find_logical_fallacies | Logikfehler finden"
"explain_docs | Dokumentation erklaeren"
"explain_terms | Glossar erstellen"
"rate_content | Qualitaets-Rating (1-10)"
"-- ZUSAMMENFASSEN ------------|"
"summarize | 1-Satz-Summary + 10 Hauptpunkte"
"create_summary | Strukturierte Zusammenfassung"
"create_5_sentence_summary | 5-Satz-Zusammenfassung"
"extract_core_message | Kernbotschaft auf den Punkt"
"-- VERGLEICHEN ---------------|"
"compare_and_contrast | Gemeinsamkeiten & Unterschiede"
"-- CONTENT ERSTELLEN ---------|"
"write_essay | Essay im Paul-Graham-Stil"
"create_keynote | Keynote erstellen"
"write_micro_essay | Micro-Essay (< 300 Woerter)"
"improve_writing | Text ueberarbeiten"
"enrich_blog_post | Blog-Post verbessern"
"create_newsletter_entry | Newsletter-Abschnitt"
"-- EXTRAHIEREN ---------------|"
"extract_ideas | 20-50 ueberraschende Ideen"
"extract_recommendations | Handlungsempfehlungen"
"extract_questions | Offene Fragen identifizieren"
"create_tags | Tags generieren"
"-- LERNEN --------------------|"
"create_flash_cards | Lernkarten erstellen"
"create_quiz | Quiz-Fragen generieren"
"-- ALLE ----------------------|"
"ALLE_PATTERNS | Alle Fabric Patterns durchsuchen"
)
local choice
choice=$(printf '%s\n' "${CURATED[@]}" | fzf \
--prompt="Pattern waehlen > " \
--header="Fabric Pattern fuer die Analyse" \
--preview='p=$(echo {} | awk "{print \$1}");
f="'"$PATTERNS_DIR"'/$p/system.md";
if [[ -f "$f" ]]; then
printf "\033[1;33m-- %s --\033[0m\n\n" "$p"
head -30 "$f"
else
echo "Kategorie-Header"
fi' \
--preview-window=right:50%:wrap \
--height=80% --border=rounded --no-multi)
[[ -z "$choice" ]] && return 1
local selected=$(echo "$choice" | awk '{print $1}')
[[ "$selected" == "--" ]] && return 1
if [[ "$selected" == "ALLE_PATTERNS" ]]; then
selected=$(ls "$PATTERNS_DIR" | fzf \
--prompt="Pattern suchen > " \
--header="Alle Fabric Patterns durchsuchen" \
--preview='...' \
--preview-window=right:50%:wrap \
--height=80% --border=rounded --no-multi)
[[ -z "$selected" ]] && return 1
fi
echo "$selected"
}
Die 7 Pattern-Kategorien
mindmap
root((Fabric Patterns))
Analysieren
extract_wisdom
extract_insights
analyze_prose
analyze_claims
find_logical_fallacies
rate_content
Zusammenfassen
summarize
create_summary
create_5_sentence_summary
extract_core_message
Vergleichen
compare_and_contrast
Content Erstellen
write_essay
create_keynote
improve_writing
enrich_blog_post
Extrahieren
extract_ideas
extract_recommendations
extract_questions
create_tags
Lernen
create_flash_cards
create_quiz
Alle
ALLE_PATTERNS
Abb. 5: Die 7 Pattern-Kategorien mit allen 28 kuratierten Patterns
Funktion 4: _obs_f_run – Batch-Modus
Was sie tut: Sammelt Dateien, oeffnet Pattern-FZF, laesst Fabric laufen, bietet Claude Handoff an.
Vollstaendiger Code
_obs_f_run() {
local mode="$1" filter="$2" pattern="$3" limit="${4:-0}" include_claude="${5:-0}"
# --- Dateien sammeln ---
local files=()
while IFS= read -r f; do
[[ -n "$f" ]] && files+=("$f")
done < <(_obs_f_collect "$mode" "$filter" "$limit" "$include_claude")
if [[ ${#files[@]} -eq 0 ]]; then
echo "Keine Dateien gefunden."
return 1
fi
echo "${#files[@]} Dateien gesammelt"
# --- Pattern waehlen via FZF ---
pattern=$(_obs_f_pick_fabric_pattern)
[[ $? -ne 0 || -z "$pattern" ]] && { echo "Abgebrochen."; return 0; }
echo "Fabric: ${pattern} (deutsch) ..."
# --- Alle Dateien durch Fabric schicken ---
local fabric_output
fabric_output=$({
echo "WICHTIG: Antworte komplett auf Deutsch."
echo ""
for f in "${files[@]}"; do
printf '\n\n--- %s ---\n\n' "$(basename "$f" .md)"
cat "$f" 2>/dev/null
done
} | "$_OBS_FABRIC_BIN" -p "$pattern")
echo "$fabric_output"
_obs_f_claude_handoff "$fabric_output" "$pattern" "${#files[@]}"
}
Datenfluss durch die Fabric-Pipe
flowchart LR
DE["Deutsch-Instruktion\nWICHTIG: Antworte\nauf Deutsch"] --> PIPE["Pipe"]
F1["Datei 1\n--- name1 ---\nInhalt"] --> PIPE
F2["Datei 2\n--- name2 ---\nInhalt"] --> PIPE
F3["Datei N\n--- nameN ---\nInhalt"] --> PIPE
PIPE --> FAB["fabric -p pattern\nz.B. extract_wisdom"]
FAB --> OUT["Fabric Output\nStrukturierte Analyse\nauf Deutsch"]
OUT --> TERM["Terminal-Ausgabe"]
OUT --> CTX["Kontext-Datei\nobs-f-context.md"]
CTX --> CC["Claude Code"]
style FAB fill:#9C27B0,stroke:#4A148C,color:#fff,stroke-width:3px
style CC fill:#2196F3,stroke:#0D47A1,color:#fff
Abb. 6: Datenfluss — Von der Deutsch-Instruktion über Fabric bis Claude Code
Funktion 5: _obs_f_claude_handoff – Claude Code Übergabe
Was sie tut: Fragt "Weiter mit Claude Code? [j/N]". Bei ja: schreibt Output in eine Datei und startet Claude Code.
_obs_f_claude_handoff() {
local output="$1" pattern="$2" file_count="$3"
echo ""
printf " -> Weiter mit Claude Code? [j/N] "
read -k1 answer # Zsh: genau 1 Zeichen lesen
echo ""
[[ "$answer" != [jJyY] ]] && return 0
# Kontext-Datei schreiben
local ctx_file="$HOME/PAI/PAI_DIRECTORY/.state/obs-f-context.md"
mkdir -p "$(dirname "$ctx_file")"
cat > "$ctx_file" <<CTXEOF
# Fabric-Analyse: $pattern
**Dateien:** $file_count | **Zeitpunkt:** $(date '+%H:%M %d.%m.%Y')
---
$output
CTXEOF
echo " Claude Code startet..."
claude "Lies die Datei $ctx_file - das ist eine Fabric-Analyse \
($pattern) meines Obsidian Vaults. Hilf mir basierend auf dieser Analyse weiter."
}
Claude Handoff Ablauf
flowchart TD
Q["Weiter mit Claude Code?\nread -k1 answer"] --> D{"Antwort?"}
D -->|"j/J/y/Y"| WRITE["Kontext-Datei schreiben\nobs-f-context.md"]
D -->|"Alles andere"| STOP["return 0\nFertig"]
WRITE --> CONTENT["Heredoc mit\nPattern + Dateianzahl\n+ Zeitstempel\n+ Fabric Output"]
CONTENT --> START["claude Befehl\nmit Verweis auf\nKontext-Datei"]
START --> CC["Claude Code\nliest Datei\nund hilft weiter"]
style Q fill:#FF9800,stroke:#E65100,color:#fff
style CC fill:#2196F3,stroke:#0D47A1,color:#fff
Abb. 7: Claude Handoff — Vom User-Prompt zur Claude Code Session
Funktion 6: _obs_f_single – Einzeldatei-Modus
Aufgerufen durch: obs-f() bei __SINGLE__-Rezepten.
_obs_f_single() {
local pattern="$1"
local file=$(_obs_f_pick_file)
[[ -z "$file" ]] && return 0
pattern=$(_obs_f_pick_fabric_pattern)
[[ $? -ne 0 || -z "$pattern" ]] && return 0
local fabric_output
fabric_output=$({
echo "WICHTIG: Antworte komplett auf Deutsch."
echo ""
cat "$file"
} | "$_OBS_FABRIC_BIN" -p "$pattern")
echo "$fabric_output"
_obs_f_claude_handoff "$fabric_output" "$pattern" "1"
}
Funktion 7: _obs_f_pick_file – Datei wählen
Was sie tut: Zeigt die 100 neuesten Obsidian-Dateien in einem FZF-Menue.
_obs_f_pick_file() {
local vault="$VAULT_AKADEMIE"
local files_json=$(_obs_eval "$vault" "JSON.stringify(
app.vault.getFiles()
.filter(f => f.extension==='md'
&& !f.path.includes('_Archive')
&& !f.path.includes('_templates')
&& !f.path.includes('.obsidian'))
.sort((a,b) => b.stat.mtime - a.stat.mtime)
.slice(0,100)
.map(f => f.path)
)")
# JSON-Array -> "pfad|ordner/name" Format fuer FZF
local file_lines=""
file_lines=$(echo "$files_json" | python3 -c "
import json, sys, os
vault = '$vault'
for p in json.load(sys.stdin):
full = os.path.join(vault, p)
name = os.path.splitext(os.path.basename(p))[0]
folder = os.path.basename(os.path.dirname(p))
print(f'{full}|{folder}/{name}')
")
echo "$file_lines" | fzf --height=30 --reverse --border \
--border-label=" Datei waehlen (100 neueste) " \
--prompt="datei > " \
--delimiter='|' \
--with-nth=2 | cut -d'|' -f1
}
--delimiter='|' und --with-nth=2 zeigen nur den schoenen Namen, geben aber den vollen Pfad zurueck.
Funktion 8: _obs_f_pick_tag – Tag/Ordner-Filter
_obs_f_pick_tag() {
local vault="$VAULT_AKADEMIE"
{
echo "marketing"
echo "kurse"
echo "wissen"
echo "strategie"
echo "content"
echo "workflows"
echo "tools"
echo "daily"
echo "--------------"
local tags_json=$(_obs_eval "$vault" "JSON.stringify(
Object.entries(app.metadataCache.getTags())
.sort((a,b) => b[1] - a[1])
.slice(0,30)
.map(e => e[0].replace('#',''))
)")
if [[ -n "$tags_json" ]]; then
echo "$tags_json" | python3 -c \
"import json,sys;[print(t) for t in json.load(sys.stdin)]"
fi
} | fzf --height=25 --reverse --border \
--border-label=" Tag/Ordner Filter " \
--prompt="filter > "
}
Eigene Patterns hinzufügen
Ins kuratierte Menue
Fuege eine Zeile ins CURATED-Array ein:
"-- MEINE KATEGORIE ----------|"
"mein_custom_pattern | Meine eigene Analyse"
Ein neues Fabric Pattern erstellen
# Ordner anlegen
mkdir -p ~/.config/fabric/patterns/mein_custom_pattern
# system.md schreiben
cat > ~/.config/fabric/patterns/mein_custom_pattern/system.md <<'EOF'
# IDENTITY and PURPOSE
Du bist ein Experte fuer [dein Thema].
# STEPS
1. Lies den gesamten Inhalt
2. Identifiziere die 5 wichtigsten Punkte
# OUTPUT FORMAT
- Ausgabe als Markdown
- Deutsche Ueberschriften
- Maximal 500 Woerter
EOF
Globale Variablen
# Vault-Pfad
VAULT_AKADEMIE="$HOME/obsidian/Claude/Akademie"
# Fabric Binary (brew-Version, nicht Anaconda)
_OBS_FABRIC_BIN="/opt/homebrew/bin/fabric-ai"
# Fabric Patterns Verzeichnis
_OBS_FABRIC_PATTERNS="$HOME/.config/fabric/patterns"
# Claude-Conversations-Schalter (Session-persistent)
_OBS_F_CLAUDE=0
Minimal-Setup zum Nachbauen
1. Datei anlegen
touch ~/.zsh/functions/obs-f.zsh
2. Minimaler Code
Kopiere _obs_f_pick_fabric_pattern, _obs_f_claude_handoff und diese vereinfachte Hauptfunktion:
obs-f() {
local vault="$HOME/obsidian/MeinVault"
local files=()
while IFS= read -r f; do
[[ -n "$f" ]] && files+=("$f")
done < <(find "$vault" -name "*.md" -mtime -1 -type f 2>/dev/null)
echo "${#files[@]} Dateien gefunden"
[[ ${#files[@]} -eq 0 ]] && return 1
local pattern=$(_obs_f_pick_fabric_pattern)
[[ -z "$pattern" ]] && return 0
local output
output=$({
echo "WICHTIG: Antworte auf Deutsch."
for f in "${files[@]}"; do
printf '\n--- %s ---\n' "$(basename "$f" .md)"
cat "$f"
done
} | fabric -p "$pattern")
echo "$output"
_obs_f_claude_handoff "$output" "$pattern" "${#files[@]}"
}
3. Laden
echo 'source ~/.zsh/functions/obs-f.zsh' >> ~/.zshrc
source ~/.zshrc
obs-f
Datei-Übersicht
| Datei | Zweck |
|---|---|
~/.zsh/functions/obsidian-vaults.zsh | Alle 8 Funktionen (Quelldatei) |
~/.config/fabric/patterns/*/system.md | 239 Fabric Pattern-Definitionen |
~/.state/obs-f-context.md | Temporaere Kontext-Datei fuer Claude Code |
~/.zshrc | Hier wird die Funktionsdatei geladen |