Projekt-Dashboard — Obsidian Bases Karten-View
Overview
Eine Karten-View in Obsidian Bases die alle aktiven Projekt-_index.md als Grid rendert. Ein lokaler launchd-Cron auf Marvins iMac scannt 2-3x täglich git log (Vault + verlinkte Code-Repos) und Claude-Code-Session-Files in ~/.claude/projects/, aktualisiert dabei Aktivitäts-Felder im jeweiligen Projekt-Frontmatter. Marvin pflegt nur next_step manuell — alles andere fliesst.
Problem Frame
Marvin verliert den Überblick über 18+ parallele Projekte und verteilte Claude-Code-Sessions. Daten existieren bereits (Frontmatter, Git-Log, Session-Files), aber ohne aggregierte Sicht. Daily-Briefing ist für den Tagesplan, nicht für „was läuft eigentlich gerade in welchem Projekt”. ADHS-Constraint: System muss unsichtbar laufen, keine Pflege-Disziplin erzwingen. Siehe origin: _index.md.
Requirements Trace
- R1 Bases-View
dashboard.baserendert alle Projekte als Karten-Grid → Unit 6 - R2 Karten zeigen Status, nächster Schritt, last_activity, sessions_24h, Kunde → Unit 1 (Schema) + Unit 6 (Layout)
- R3 Klick auf Karte öffnet
_index.md→ Unit 6 - R4 Filter zeigt nur
status != archiviert/done→ Unit 6 - R5 Default-Sort nach last_activity_at absteigend → Unit 6
- R6 Frontmatter-Erweiterung um Activity-Felder → Unit 1
- R7
next_stepbleibt manuell → Unit 4 (Writer überschreibt es nie) - R8 Cron läuft 2-3x täglich → Unit 5
- R9 Datenquellen MVP:
git log+ Claude-Sessions → Unit 2 + Unit 3 - R10 Frontmatter-Updates dürfen committet werden (optional, Phase 2) → Open Question, default OFF im MVP
- R11
code_repos: [<slug>...]mappt Projekt zu Source-Repos → Unit 1 + Unit 2
Scope Boundaries
- Kein Cross-Project-Kanban, keine Timeline-View, keine Live-Ops-Sicht
- Kein Web-Dashboard, kein Mac-Widget, kein Mobile
- Keine Telegram/Kalender/Mail-Quellen im MVP (Phase 2/3)
- Kein Auto-Generieren von
next_step - Kein Git-Commit aus dem Cron im MVP (siehe Open Question)
- Keine Backwards-Compat-Migration alter Frontmatter-Felder (nur additive Ergänzung)
Context & Research
Relevant Code and Patterns
- _index.md — Frontmatter-Pattern für Projekte (
id,type: project,status,description,related) - _index.md — komplexere Variante mit
customer,phase,budget - lokale-source-repos.md — kanonische Liste der lokalen Code-Repos (Strategie-Kern, MCPs, Kunden)
- schemas.md — Frontmatter-Schemas pro Entity-Typ; muss um neue Felder ergänzt werden
- agents-platform — Cron-Pattern (Lambda), nicht für diesen Plan verwendet weil Sessions lokal liegen
Frontmatter-Variabilität: Aktive Projekte nutzen unterschiedliche Title-Felder (title, name) und unterschiedliche id-Prefixes (proj-YYYY-NNN, proj-<slug>, doc-...). Der Scanner muss tolerant lesen.
Institutional Learnings
- Marvins ADHS-Pattern (Memory): „System möglichst unsichtbar”. Heisst: kein Approval-Dialog im Cron, keine Notifications für Routine-Updates, kein Pflege-Zwang
- Vault-Regel 18: NIE in
~/.claude/projects/memory/schreiben — Cron schreibt nur in Vault-Files - Vault-Konvention: Wikilinks in YAML als Strings (
"[[acme]]")
External References
- Obsidian Bases — Syntax —
.base-File-Format (YAML,views: - type: cards) - Obsidian Bases — Functions — Filter-Funktionen, Date-Math
- Bases Migration / Quick Start
- Inside Claude Code: Session File Format
- daaain/claude-code-log — Python-Pattern zum Scannen aller Sessions, gutes Vorbild für Scan-Loop
- Bas-Man: launchd statt crontab — macOS-Best-Practices:
StartCalendarInterval, explizitePATH, Lockfile,plutil -lintvor Load - Lokaler Skill:
obsidian:obsidian-bases— beim Bauen der.base-Datei aufrufen, hat Card-Layout-Details die online nur dünn dokumentiert sind
Key Technical Decisions
- Cron läuft lokal via
launchd(LaunchAgent), nicht AWS-Lambda. Sessions liegen in~/.claude/projects/, Lambda kann das nicht lesen. Lokal hat zusätzlich den Vorteil dassgit logohne API-Calls läuft. cwdaus erster JSONL-Zeile als Repo-Identifier, nicht Ordner-Name-Decoding. Path-Encoding ist verlustbehaftet (Original-Pfade mit Dashes nicht reversibel). Erste Zeile enthältcwdder Session.- Scanner = einzelnes Python-Skript (keine Module-Pyramide). Layer-Code aus
agents-platform/layers/agentic-common/wird nicht wiederverwendet — der Scanner hat keine MCP/Bedrock-Abhängigkeiten, kein Bedarf für den Layer. - Kein Git-Commit aus dem Cron im MVP. Verhindert Konflikte mit Marvins Live-Edits + Daily-Briefing-Lambda-Commits. Frontmatter-Updates bleiben lokal als „dirty changes” sichtbar — Marvin committet selbst (oder nicht, irrelevant für Bases-Rendering).
- Schreib-Strategie: in-place Frontmatter-Edit mit Idempotenz. Skript liest YAML-Block, mergt die 4 Activity-Felder, schreibt zurück.
next_stepund alle anderen Felder bleiben unangetastet. - Card-Layout via
order: [status, next_step, file.mtime, formula.activity_label]— Bases gibt nur eine Reihenfolge vor, kein freies Layout. Eineformulabaut „vor 3h” oder „gestern” auslast_activity_at. code_repos: []im Frontmatter pflegt Marvin manuell (3-5 aktive Projekte initial, einmaliger Setup-Aufwand). Wenn leer, scannt nur Vault-Ordner.
Open Questions
Resolved During Planning
- Wo läuft der Cron? Lokal als
launchdLaunchAgent. Begründung: Sessions sind lokal-only. - Was definiert „last_activity”? Maximum-Timestamp aus: letzter Git-Commit-Date (Vault-Ordner +
code_repos) ODER letzte Session-Aktivität (letzte JSONL-Zeile-Timestamp).last_activity_sourcemarkiert welche Quelle gewann. - Was steht in
last_activity_summary? Beisource=commit: erste Zeile der Commit-Msg. Beisource=claude-session:ai-titleaus der ersten Zeile des JSONL. - Wie wird
sessions_24hermittelt? Anzahl uniquesessionIdin~/.claude/projects/<encoded>/*.jsonlderen Last-Line-Timestamp innerhalb der letzten 24h liegt. Skript geht nur über Sessions, derencwdincode_reposdes Projekts steht.
Deferred to Implementation
- Genaues
.base-Card-Layout (welche Property prominent, Sortier-Direction): Im Unit 6 mitobsidian:obsidian-bases-Skill iterieren bis es visuell passt - Behandlung von Projekten ohne
code_repos-Feld: Sind das alle aktiven? Erst migrieren (Unit 1) und im Cron-Skript einen Fallback (vault-only) bauen - YAML-Library-Wahl:
ruamel.yaml(preserves comments + key-order) vspython-frontmatter(simpler, drops kommentare). Entscheidung in Unit 4 — direkt anhand realer_index.mdtesten - Performance bei vielen Sessions: Aktuell ~150 JSONL-Files in
~/.claude/projects/. Wenn der Scanner > 5 Sekunden braucht, Caching auf File-mtime einbauen — Detail für Unit 3 - Wie reagiert der Scanner wenn ein Projekt verschoben/umbenannt wurde? Edge-Case in Unit 4 — neue Felder einfach setzen, kein Cleanup
High-Level Technical Design
Directional guidance, keine Implementation-Spec.
LaunchAgent (com.agenticventures.dashboard-scan.plist)
├─ trigger: StartCalendarInterval [06:00, 12:00, 18:00 Berlin]
└─ ruft scripts/dashboard-scan.py auf
│
├─ liest intern/firma/lokale-source-repos.md (Repo-Liste)
│
├─ für jedes Projekt in intern/projekte/<slug>/_index.md:
│ ├─ parsiert frontmatter (code_repos, current activity fields)
│ ├─ ermittelt git_activity:
│ │ ├─ git log -1 --format=%ct\|%s in <vault-projekt-ordner>
│ │ └─ git log -1 --format=%ct\|%s in jedem code_repos[i]
│ ├─ ermittelt claude_activity:
│ │ ├─ für jeden code_repo: encode path → ~/.claude/projects/<encoded>/
│ │ ├─ liest letzte Zeile jeder *.jsonl, sammelt timestamps
│ │ ├─ liest erste Zeile für ai-title (Session-Name)
│ │ └─ zählt sessions_24h
│ ├─ wählt max-timestamp Quelle → last_activity_source
│ └─ mergt in frontmatter, schreibt _index.md zurück
│
└─ schreibt scan-log nach intern/runs/dashboard-scan/<datum>.md
Obsidian (Marvin's iMac, offen)
└─ rendert dashboard.base
├─ source: alle intern/projekte/**/_index.md mit type:project
├─ filter: status NICHT IN [archiviert, done]
├─ sort: last_activity_at DESC
└─ view cards: Status-Badge + Title + next_step + "vor 3h via Session"
Implementation Units
flowchart TB U1[Unit 1: Schema-Erweiterung] --> U2[Unit 2: Repo-Mapping-Pflege] U1 --> U6[Unit 6: dashboard.base] U2 --> U3[Unit 3: Activity-Scanner] U3 --> U4[Unit 4: Frontmatter-Writer] U4 --> U5[Unit 5: LaunchAgent] U5 --> U7[Unit 7: Smoke-Test] U6 --> U7
- Unit 1: Schema-Erweiterung um Activity-Felder + code_repos
Goal: Neue Frontmatter-Felder in _meta/schemas.md dokumentieren und in _meta/conventions.md referenzieren. Optional-Markierung, additiv.
Requirements: R6, R11
Dependencies: Keine
Files:
- Modify:
_meta/schemas.md(Sektion 5.5 Project erweitern um Activity-Felder +code_repos) - Modify:
_meta/conventions.mdfalls dort Naming-Regeln stehen die referenziert werden müssen
Approach:
- Neue Felder dokumentieren:
last_activity_at(ISO-8601 datetime),last_activity_source(Enum:commit|claude-session|manual|none),last_activity_summary(string, max 100 Chars),sessions_24h(int),next_step(string, 1 Zeile),code_repos(Liste von Repo-Slugs ausintern/firma/lokale-source-repos.md) - Alle Activity-Felder als „auto-managed by dashboard-scan, nicht manuell editieren” markieren
next_stepundcode_reposals manuell-gepflegt markieren
Patterns to follow:
- Bestehende Schema-Definitionen in
_meta/schemas.md(Sektion 5.1-5.5) - Wikilink-as-string-Konvention
Test scenarios:
- Test expectation: none — reine Doku-Änderung
Verification:
-
_meta/schemas.mdenthält Sektion mit allen neuen Feldern + Auto-Managed-Hinweis -
Beispiel-Frontmatter mit allen neuen Feldern ist im Schema-Block sichtbar
-
Unit 2: code_repos-Mapping in aktiven Projekt-
_index.mdpflegen
Goal: Manuelle Migration: in jedem intern/projekte/<slug>/_index.md mit status: active das Feld code_repos: [...] hinzufügen. Für Projekte ohne Code-Repo bleibt das Array leer.
Requirements: R11
Dependencies: Unit 1
Files:
- Modify: alle
intern/projekte/*/_index.mdmitstatus: active(etwa 8-12 Stück)
Approach:
- Pro Projekt entscheiden welche Repos relevant sind. Referenz: lokale-source-repos.md
- Beispiele:
bas-twin: ["bas-twin"],mcp-pipeline-aws: ["mcps", "agents-platform"],daily-briefing: ["agents-platform"],av-website: ["agentic-ventures-website"] - Falls Projekt nur im Vault lebt (Doku-Projekte):
code_repos: []
Patterns to follow:
- Bestehende
related:-Listen mit Wikilinks als Vorbild für Listen-Format
Test scenarios:
- Test expectation: none — manuelle Daten-Pflege
Verification:
-
Jedes aktive Projekt-
_index.mdhatcode_repos:Feld (auch wenn[]) -
Repo-Namen matchen die Ordner in
~/source/(kein Tippfehler) -
Unit 3: Activity-Scanner (Python-Skript)
Goal: Pures Python-Skript das pro Projekt die Activity-Daten ermittelt. Liest, schreibt nicht — Output ist ein Dictionary pro Projekt.
Requirements: R8, R9
Dependencies: Unit 2 (braucht code_repos als Input)
Files:
- Create:
scripts/dashboard-scan/scan.py(im Vault-Repo unterscripts/dashboard-scan/) - Create:
scripts/dashboard-scan/README.md(kurze Doku: was, wie aufrufen, dependencies) - Create:
scripts/dashboard-scan/requirements.txt(ruamel.yamlfalls gewählt, sonst stdlib only) - Test:
scripts/dashboard-scan/test_scan.py
Approach:
- Function
scan_project(project_path: Path) -> dictliest Frontmatter, ermittelt Activity, gibt Dict mit den 4 Activity-Feldern zurück - Function
git_last_activity(repo_path: Path) -> tuple[datetime, str]ruftgit log -1 --format=%cI|%sviasubprocess.run, parst Output - Function
claude_sessions_for_repo(repo_abs_path: Path) -> list[dict]encodiert Pfad mitreplace("/", "-"), sammelt JSONL-Files in~/.claude/projects/<encoded>/ - Pro JSONL-File: letzte Zeile via
tail-equivalent (read last N bytes) → JSON-Parse → Timestamp. Erste Zeile (fallsai-title) → Session-Name - Aggregation: max-timestamp gewinnt,
last_activity_sourcemarkiert Herkunft.sessions_24h= count(sessions where last_ts > now - 24h) - Kein Schreibzugriff in dieser Unit — reines Lese-Modul, gibt Daten zurück. Schreibzugriff in Unit 4
Patterns to follow:
- daaain/claude-code-log Scan-Loop als Vorbild
- Defensives Parsing: skip-on-error pro Session (eine kaputte JSONL bricht nicht den ganzen Scan)
Test scenarios:
- Happy path: Projekt mit
code_repos: ["bas-twin"]+ existierende Sessions liefert korrektelast_activity_at+source+summary - Happy path: Projekt mit
code_repos: []und kein Vault-Ordner-Commit liefertlast_activity_source: "none" - Edge case: Projekt-Vault-Ordner ohne Commits (frisch angelegt) liefert keine git-Aktivität, fällt auf Sessions zurück
- Edge case: Kaputte JSONL-Datei (truncated) wird übersprungen, Skript läuft weiter
- Edge case:
~/.claude/projects/<encoded>/existiert nicht (nie damit gearbeitet) → leere Session-Liste, kein Crash - Error path:
git logschlägt fehl (nicht-Git-Ordner) → catch, return None, kein Crash - Integration: Scanner über alle aktiven Projekte läuft < 10s auf Marvins iMac
Verification:
-
python scripts/dashboard-scan/scan.py --dry-runprintet pro aktivem Projekt ein dict mit 4 korrekten Activity-Feldern -
Tests:
pytest scripts/dashboard-scan/test_scan.pygrün -
Unit 4: Frontmatter-Writer (in-place Merge)
Goal: Schreibt die 4 Activity-Felder zurück in _index.md, lässt alle anderen Felder + Markdown-Body unangetastet.
Requirements: R6, R7
Dependencies: Unit 3
Files:
- Modify:
scripts/dashboard-scan/scan.py(ergänzt umwrite_frontmatter(path, fields)) - Test:
scripts/dashboard-scan/test_scan.py(Tests für Writer)
Approach:
- YAML-Library-Wahl in Implementation (siehe Open Question):
ruamel.yamlbevorzugt wegen Erhalt von Kommentaren + Key-Order, fallbackpython-frontmatterfalls Setup-Hürde - Read-Merge-Write: Frontmatter parsen, 4 Activity-Felder setzen/überschreiben, keine anderen Felder anfassen (auch nicht
next_step) - Wenn Feld vorher nicht existierte: hinzufügen am Ende des Frontmatter-Blocks
- Atomic write: schreibe in Temp-File, dann
os.replace— verhindert Half-Writes wenn Obsidian gerade liest --dry-runFlag zeigt Diff statt zu schreiben
Patterns to follow:
- Atomic-write Pattern (
tempfile.NamedTemporaryFile+os.replace)
Test scenarios:
- Happy path: Bestehende
_index.mdmit minimalem Frontmatter wird um Activity-Felder ergänzt, Body unverändert - Happy path:
_index.mdmit bestehenden Activity-Feldern wird aktualisiert (Werte ersetzt, nicht dupliziert) - Edge case:
next_stepist gesetzt — Writer fasst es nicht an - Edge case: Frontmatter mit Wikilink-Strings (
customer: "[[becker]]") bleibt nach Roundtrip intakt (Quotes erhalten) - Edge case: Frontmatter mit YAML-Listen mehrzeilig (
team: \n - "[[marvin]]") bleibt erhalten - Edge case: File hat Kommentare im Frontmatter → bleiben erhalten (ruamel) oder dokumentierte Lossy-Behavior (frontmatter)
- Error path: File existiert nicht → loggen, skip, kein Crash
- Error path: Frontmatter-Block kaputt (kein schliessendes
---) → loggen, skip - Integration: Komplett-Run über alle aktiven Projekte,
git diffzeigt nur Activity-Field-Änderungen
Verification:
-
Nach
python scripts/dashboard-scan/scan.pyzeigtgit diff intern/projekte/ausschliesslich Änderungen in den 4 Activity-Feldern -
Markdown-Body von 5 Stichproben-Projekten ist Byte-gleich vor und nach Scan
-
Unit 5: LaunchAgent + Wrapper-Skript
Goal: macOS LaunchAgent das den Scanner 3x täglich startet, mit Lockfile, sauberer PATH, Logs in Vault.
Requirements: R8
Dependencies: Unit 4
Files:
- Create:
scripts/dashboard-scan/run.sh(Wrapper mit Lockfile + Env-Setup + Logging) - Create:
scripts/dashboard-scan/com.agenticventures.dashboard-scan.plist(Template, wird in~/Library/LaunchAgents/symlinked oder kopiert) - Create:
scripts/dashboard-scan/install.sh(One-shot Installer: copy/symlink +launchctl load) - Create:
scripts/dashboard-scan/uninstall.sh(launchctl unload+ cleanup) - Modify:
intern/firma/stack.md(LaunchAgent-Eintrag dokumentieren, falls Stack-Inventory dort)
Approach:
- plist:
StartCalendarIntervalmit drei Slots (06:00, 12:00, 18:00).StandardOutPathundStandardErrorPathzeigen auf~/Library/Logs/dashboard-scan.log RunAtLoad: false(kein Spam beim Login)EnvironmentVariables: setzePATH=/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin,HOME- Wrapper
run.sh:- Lockfile via
flockodermkdir-Trick — wenn schon läuft, exit 0 cd $VAULT_PATHpython3 scripts/dashboard-scan/scan.py >> log 2>&1- Lock release
- Lockfile via
- Installer:
plutil -lintvor Load, Pfad-Check, idempotent (uninstall vorher)
Patterns to follow:
- Bas-Man’s launchd-Best-Practices (Linked Source)
- Existierende
~/Library/LaunchAgents/-Konventionen (Reverse-FQDN-Naming)
Test scenarios:
- Happy path:
install.shlegt plist an,launchctl list | grep dashboard-scanzeigt geladenen Agent - Happy path: Manueller Trigger via
launchctl start com.agenticventures.dashboard-scanläuft erfolgreich, Log zeigt Scan-Output - Edge case: Zweiter Trigger während erster läuft (Lock-File greift) → exit ohne Doppellauf
- Edge case:
python3nicht im PATH → Wrapper loggt Fehler verständlich (nicht silent fail) - Error path: Vault-Repo hat uncommitted Changes — Skript läuft trotzdem (es committet nichts)
- Integration: Nach Install läuft der Scan zum nächsten Slot automatisch ohne manuelles Eingreifen
- Uninstall:
uninstall.shentfernt plist + entlädt Agent,launchctl listzeigt ihn nicht mehr
Verification:
-
plutil -lint scripts/dashboard-scan/com.agenticventures.dashboard-scan.plist→ OK -
Nach Manual-Trigger:
intern/projekte/*/index.mdhaben aktualisierte Activity-Felder,~/Library/Logs/dashboard-scan.logzeigt sauberen Run -
Unit 6: dashboard.base (Obsidian Bases Card-View)
Goal: Eine .base-Datei im Vault die das Karten-Grid rendert.
Requirements: R1, R2, R3, R4, R5
Dependencies: Unit 1 (Schema), parallel zu Unit 2-5 möglich
Files:
- Create:
dashboard.baseim Vault-Root (oderintern/dashboard.base— Decision in Implementation, je nach Obsidian-Konvention) - Optional:
intern/_context.mdergänzen mit Hinweis auf die Base
Approach:
- Vor dem Bau: den Skill
obsidian:obsidian-basesaufrufen, der hat die Card-Layout-Feinheiten - Top-Level:
filters,formulas,views - Filter:
and: ['type == "project"', 'status != "archiviert"', 'status != "done"'] - Formula
activity_label: konvertiertlast_activity_atin „vor X Stunden/Tagen/manual” - View
type: cards,name: "Aktive Projekte",sort: [{property: last_activity_at, direction: DESC}] order: [status, title, next_step, formula.activity_label, sessions_24h, customer]- Tests visuell in Obsidian — keine Unit-Tests möglich
Patterns to follow:
- Offizielle Obsidian-Bases-Beispiele
- Lokaler Skill
obsidian:obsidian-bases
Test scenarios:
- Test expectation: visual — keine Code-Tests. Aber Akzeptanzkriterien:
- Visual: Bei Öffnen rendern alle aktiven Projekte als Karten
- Visual: Archivierte und done-Projekte erscheinen nicht
- Visual: Karten sind nach Activity sortiert (frischestes oben)
- Visual: Klick auf eine Karte öffnet
_index.md - Visual:
next_step-Zeile ist prominent lesbar
Verification:
-
Marvin öffnet die Base in Obsidian → Karten sind sichtbar, sortiert, gefiltert
-
Manuelles Setzen
status: donein einer Projekt-_index.mdlässt Karte verschwinden ohne Reload -
Unit 7: End-to-End Smoke-Test + Doku
Goal: Verifikation dass alle Units zusammen funktionieren. Doku in Vault.
Requirements: S1, S2, S3, S4
Dependencies: Unit 5, Unit 6
Files:
- Modify:
intern/projekte/projekt-dashboard/_index.md(status →deployed, Dokumentation der Setup-Schritte) - Create:
intern/projekte/projekt-dashboard/runbook.md(Wie Re-Run? Wie debuggen? Wie deaktivieren?) - Modify:
intern/wissen/prozesse/ggf. Eintrag für „Pattern: lokaler Cron schreibt Vault-Frontmatter” falls wiederverwendbar - Modify: CLAUDE.md Routing-Tabelle: Zeile „Projekt-Dashboard” ergänzen
Approach:
- Trigger einen vollen Scan manuell, prüfe Frontmatter in 5 Stichproben
- Setze einen Projekt-Status auf
archiviert, prüfe dass Karte verschwindet - Editiere
next_stepin einem Projekt, prüfe dass Karte das anzeigt - 24h-Wartetest: ein automatischer Trigger läuft, Logs sehen sauber aus
Test scenarios:
- Happy path: Voller Scan + Bases-View zeigt frische Daten
- Integration: Marvin pflegt
next_stepper Hand — bleibt erhalten über mehrere Scans - Integration: Neue Session in Claude Code → nächster Scan registriert sie im
sessions_24h-Counter - Edge case: Marvin verschiebt ein Projekt-Ordner — Scanner bricht nicht, neues Projekt erscheint, altes verschwindet (oder bleibt mit veralteten Daten — dokumentieren)
Verification:
- S1 erfüllt: morgendliches Öffnen der Base zeigt sofort welche Projekte gestern Activity hatten
- S2 erfüllt: Drift zwischen
last_activity_atund realem letzten Commit < 12h - S3 erfüllt: Marvin pflegt nur
next_step(gemessen über 1 Woche) - S4 erfüllt: Karte zeigt „letzte Session: ‘Set up AWS MCP and organize multi-customer accounts’ (vor 3h)” — direkt klickbare Antwort auf „welche Session war das?”
System-Wide Impact
- Interaction graph: Frontmatter-Updates ändern alle aktiven Projekt-
_index.md. Daily-Briefing-Lambda liest aktuelloperations/action-items.mdvia GitHub-API — wird nicht beeinflusst. Andere Vault-Konsumenten (manuelles Lesen, andere Skills) sehen lediglich zusätzliche Felder. - Error propagation: Scanner-Fehler dürfen nicht die
_index.md-Dateien beschädigen. Atomic Writes + Skip-on-Error pro Projekt sind Pflicht. Wenn Scanner ganz crasht, bleibt der Vault-State unverändert. - State lifecycle risks: Konflikt-Risiko zwischen Cron-Writes und Marvin-Live-Edits in Obsidian. Mitigation: kein Git-Commit aus Cron, kein File-Lock — letzter Writer gewinnt. Obsidian-File-Watch greift, Marvin sieht updates live. Wenn Marvin gerade tippt und Scanner schreibt: Obsidian merged in den meisten Fällen sauber, im Worst-Case sieht Marvin einen Sync-Konflikt-Dialog (selten bei 3 Scans/Tag).
- API surface parity: Keine externen API-Konsumenten. Vault-Schema bleibt rückwärtskompatibel (additive Felder).
- Integration coverage: Cross-Layer-Test: Scanner schreibt → Obsidian-Bases liest → Marvin sieht. Nur via Manual-Test verifizierbar.
- Unchanged invariants: Bestehende Frontmatter-Felder (
id,type,status,customer, etc.) werden nie überschrieben. Markdown-Body wird nie angefasst. Daily-Briefing-Cron + Beleg-Pipeline laufen unverändert weiter.
Risks & Dependencies
| Risk | Mitigation |
|---|---|
Scanner beschädigt _index.md-Dateien (kaputtes YAML) | Atomic Write + Roundtrip-Test im Unit-Test-Setup. Vor erstem Live-Run: Trockenlauf gegen Backup-Kopie des Vaults |
| Konflikt mit Marvins gleichzeitigen Edits | Cron läuft 3x täglich zu festen Zeiten (6/12/18 Uhr) — Marvin kann manuell pausieren via launchctl unload. Plus: kein Git-Commit aus Cron, lokale Diffs sichtbar |
| Obsidian Bases hat noch Rough-Edges (relativ neue Feature) | Skill obsidian:obsidian-bases beim Bauen nutzen + bei Bugs einfache YAML-Anpassung im .base-File |
code_repos-Pflege wird vergessen → veraltete Karten | Scanner loggt explizit „Projekt X hat keine code_repos und keinen Vault-Commit seit 30 Tagen” als Hinweis in Telegram falls gewünscht (Phase 2) |
| LaunchAgent läuft nicht weil iMac in Sleep | StartCalendarInterval queued bei Wake — built-in Behavior, keine extra Action |
| Sessions-Files bekommen ein neues Format (Anthropic-Update) | Scanner defensive parsing, skip-on-error pro File. Bei breaking change: in Unit 3 Stelle das Parsing-Tolerance einbauen |
Documentation / Operational Notes
- Routing-Eintrag in
CLAUDE.md: „Projekt-Dashboard / Cron-Scan” → diese Plan-Datei + Runbook - Schema-Doku in
_meta/schemas.mdmuss Activity-Felder als „auto-managed” markieren (Unit 1) - Runbook in
intern/projekte/projekt-dashboard/runbook.md: wie pausieren, wie debuggen, wie deinstallieren - Logs in
~/Library/Logs/dashboard-scan.log— bei Bedarf rotation vianewsyslog(Phase 2) - Wenn Phase 2 (Telegram-Stream) kommt: agents-platform Lambda könnte Telegram-Pushes lesen und ans Vault-File koppeln (Cross-Source-Aggregation) — Open Design für später
Sources & References
- Origin document: _index.md
- Related Vault: lokale-source-repos.md, schemas.md
- Related project: _index.md (Schema-Vorbild, aber anderes Cron-Pattern)
- External: Obsidian Bases Syntax, Claude Code Session File Format, daaain/claude-code-log, Bas-Man launchd Guide
- Skill für Implementierung:
obsidian:obsidian-bases(lokal verfügbar)