A single-purpose, headless Raspberry Pi 4 that serves as always-on knowledge infrastructure: continuous two-vault Obsidian sync, local offline audio transcription, and direct AI (Claude Code) access to a plain-markdown knowledge base.
Design goal: the machine is disposable, the data is not. A dead SD card is a <1 hour recovery: flash fresh OS → scripts/bootstrap.sh → restic restore → operational.
iPhone ───────┐ ┌─────── Desktop (Claude Code + MCP)
(capture) │ Obsidian Sync (cloud) │
└──────────────┬───────────────┘
│
┌─────────▼──────────┐
│ ARISTOTLE │ Pi 4 8GB · PoE+ HAT · rack-mounted
│ RPi OS Lite 64-bit │ headless · SSH key-only · Tailscale
├────────────────────┤
│ obsidian-headless │ 2x systemd sync services
│ Claude Code │ `brain` / `work` shell aliases
│ Whisper (base/CPU) │ path-unit watches audio-inbox/
├────────────────────┤
│ SSD @ /mnt/m2 │ fstab nofail + wait-oneshot guard
│ ├── vaults/ │ (solves USB enumeration race)
│ ├── library/ │ PDFs, kept off cloud sync
│ └── audio-inbox/ │ voice memos → transcripts
└─────────┬──────────┘
│ nightly restic (encrypted) over Tailscale
▼
Backup target on desktop
One node, one job. This is deliberately not a general homelab server — see docs/decisions/001.
- USB boot race, solved properly-enough:
fstabwithnofail,x-systemd.device-timeout=60plus a polling oneshot (wait-for-m2.service) gating the sync services. Why not systemd mount units? ADR 004 — shell escaping of mount-unit names lost to pragmatism. - Whisper on ARM/CPU: base model, PyTorch reinstalled from the CPU wheel index, FP32 fallback. Turbo model measured as unusable on Pi 4. ADR 005.
- Local LLM rejected on evidence: 93s for trivial inference on Pi 4 CPU. Cloud AI for reasoning, local processing only where data sensitivity demands it. ADR 006.
- Failure alerts that ride the sync system:
OnFailure=on the sync units writes into the vault itself — the alert lands where I already look daily. No monitoring stack for two services.
docs/ architecture, full setup guide, decision records (ADRs)
config/ sanitized live configs: systemd units, fstab, aliases, sshd hardening
scripts/ bootstrap.sh (rebuild) · harvest.sh (live→repo) · backup.sh · transcribe
Personal values (UUIDs, IPs, hostnames) are {{PLACEHOLDER}} tokens substituted at deploy time from an uncommitted aristotle.env. Vault contents are not part of this repo and never will be — this repo is the machine, not the notes.
See docs/setup.md. Short version: Pi 4 + SSD + Raspberry Pi Imager (key-only SSH), then bootstrap.sh does the rest idempotently. You'll need your own Obsidian Sync account for the sync layer, or swap in Syncthing.
Live and in daily use. Roadmap gated behind usage triggers, not enthusiasm: RAG pipeline over the PDF library (trigger: 200+ notes / 50+ PDFs), VLAN isolation with proper inter-VLAN rules (ADR 007).