ATHENS (formerly Athenaeum) is a private, local-first macOS document library. It imports personal and business documents into a sandboxed vault, extracts searchable text, applies local AI-assisted metadata, and lets you ask questions across the archive with on-device retrieval-augmented generation.
The app is built with SwiftUI, SwiftData, Vision, PDFKit, and a bundled llama.cpp framework for GGUF model inference. It is designed around the idea that sensitive documents should stay on the Mac.
Privacy policy: shawhause.com/athens-privacy.html
2.11.0 — Tag Chat.
Chat now includes an optional Tag Chat filter. Users can select one or more document tags, and local RAG retrieval only uses processed documents with at least one selected tag. Clearing the filter returns chat to the full indexed archive.
2.10.1 — AI disclaimer surfaces.
Chat, onboarding, Help, AI settings, model status, document summaries, and AI rename review now show a consistent disclaimer: ATHENS can make mistakes, source documents should be verified, and outputs are not legal, medical, tax, or financial advice.
2.13.0 — "For This Mac" headroom: idle unload, memory-pressure response, P-core-aware threading, lifecycle hardening.
Local models now scale to the host Mac and stay out of its way, in the spirit of a "For This Mac" preset. The CPU thread budget is capped per tier and never exceeds performance-core count minus one — efficiency cores and one P-core always stay free for the rest of the system (the old formula counted E-cores and saturated an M2 Air). Loaded models automatically release their multi-gigabyte unified-memory footprint after a tier-scaled idle window (5–20 min), immediately under macOS memory pressure, and when the last window closes; the next request transparently reloads (~5–15 s warmup). On quit, any running
whisper-clichild process is now terminated (macOS doesn't kill children of a quit app), and whisper waits are async instead of parking a thread. Also fixed: per-call temperature/top-p was silently ignored because the sampler chain was built once at load — it's now built per generation call, so tagging (temp 0.1) and chat (temp 0.7) each get correct sampling even when sharing one context. The Settings tier picker's auto option is now labeled "For This Mac (Recommended)".
2.12.0 — Local media transcription MVP.
ATHENS can now import common audio and video files and route them through the document pipeline as transcripts when local
whisper-cliand a GGML Whisper model are installed. Transcripts become searchable text, feed tagging and summaries, and are indexed for RAG chat. For this MVP, placewhisper-cliunder~/Library/Application Support/Athenaeum/Whisper/or use Homebrew'swhisper-cli; place a model such asggml-small.en.binunder~/Library/Application Support/Athenaeum/Whisper/Models/.
2.9.3 — Onboarding trust screen.
Onboarding now includes a privacy trust screen before the import step, making the local-first contract explicit: documents, originals, metadata, vector indexes, and AI processing stay on the Mac, and users can export or delete their data anytime.
2.10.0 — Encrypted migration backup.
Settings → Storage now includes a one-click encrypted backup flow. ATHENS writes a passphrase-protected
.athensbackuparchive containing vault originals, a SwiftData JSON snapshot of documents/tags/folders/word-bank/chat records, recovered in-database originals when vault files are missing, and localvector_store*.jsonfiles for moving a library to a new Mac.
2.9.2 — Local model shutdown on quit.
ATHENS now registers its llama.cpp runtime with the macOS app lifecycle. When the app quits, active chat streams are canceled, in-flight vision model loads are stopped, and every loaded local LLM context is unloaded before macOS completes termination. The local model service is registered again on app launch so tagging, OCR cleanup, embeddings, and chat can warm up normally when the app is open.
2.9.1 — Direct AirDrop from documents.
Document right-click menus now include a native AirDrop action that sends the original file directly to nearby Apple devices. The existing macOS Share Sheet remains available for Mail, Messages, Notes, AirDrop, and third-party share extensions.
2.4.0 / 2.4.1 — Mac App Store readiness sweep.
Submission gates: bundle identifier moved from the placeholder
marcshaw.Athenaeumto the reverse-DNScom.shawhause.athens; newPrivacyInfo.xcprivacydeclares the two required-reason APIs the app actually uses (UserDefaults, FileTimestamp);CFBundleDisplayNameandNSHumanReadableCopyrightnow live inInfo.plistwhere they're actually picked up;LSApplicationCategoryTypereconciled toproductivity;MACOSX_DEPLOYMENT_TARGETwidened from 15.7 to 15.0; unusedfiles.downloads.read-writeandREGISTER_APP_GROUPSentitlements dropped.Crash bugs:
LlamaContext.loadnow defer-rolls back partial model/sampler allocations on a thrown step; thebatch.seq_id[idx]!force-unwrap is gone;generateStream's producer task is gated by an in-flight counter sounload()waits for it before freeing pointers;llama_backend_initis once-per-process;ModelDownloader.DownloadDelegatelocks its concurrent dictionaries.Privacy regression closed: tagging-pipeline content (titles, summaries, correspondents) no longer mirrors to system-wide
NSLogin release builds. The on-disktagger.logstays (the published policy explicitly covers it; it never leaves the Mac) and now rotates at 2 MB. Hugging Face downloads pick up an HTTPS redirect-host allowlist (HF +*.huggingface.co/*.hf.co/*.cloudfront.net), a streaming SHA-256 verifier whoseexpectedSHA256is per-descriptor optional, and a 250 MB import-size cap. PDF OCR is bounded by page count (200) and per-page pixel area so a malicious PDF can't request a 400 GB bitmap.Hardening:
DocumentVaultService.isInVaultresolves symlinks before containment-checking (a symlink dropped in the vault can no longer redirect a delete outside it);BatchProcessor.exportDocumentsstrips path components from user-editable filenames;AutoScanCoordinatorfilters symlinks during scan, bounds its fingerprint set at 50k entries, pairs everystartAccessingSecurityScopedResourcewith astop, and moves FSEvents teardown to a nonisolated holder so Swift 6 strict concurrency is happy.Code quality:
LocalLLMServicesingle-flight gates concurrent first-OCR callers so the 5 GB vision model isn't double-loaded; vault-path help copy corrected to reflect the sandboxed container (not the misleading~/Documents/Athenaeum Libraryclaim);ThumbnailGeneratorswapped its unbounded dictionary forNSCache(countLimit 512, ~256 MB totalCostLimit);Localizable.xcstringsscaffold added; the RAG system prompt now fences document context in<document_context>tags with explicit instructions to ignore embedded directives. Light-mode contrast bumped on the two color tokens that were failing WCAG AA (textTertiaryFB3.4:1 → 4.6:1,accentMutedFallback2.4:1 → 4.7:1). The asset catalog's misnamedDestructive(was blue) andSuccess(was a duplicate of AccentColor) colorsets now actually look destructive and successful.Known remaining work for full MAS submission: the embedded
llama.xcframeworkis ad-hoc signed (codesign -dvvreportsSignature=adhoc, Identifier=stripped_lib) — it must be re-signed with the developer team identity or re-built from source before archive upload, otherwise MAS validation will reject the embedded binary. SHA-256 values inHFModelInfo.entriesare intentionallyniluntil the canonical model files are verified against the upstream Hugging Face repos. Bundle ID change is breaking for existing installs — the sandbox container path changes (marcshaw.Athenaeum→com.shawhause.athens), so any pre-2.4.0 user data needs to be re-imported.
2.3.0 — tier-driven runtime + icon-picker polish. The Hardware Tier picker now adapts both the model lineup and the runtime shape of every chat: chunk size, retrieval top-K, per-chunk and total prompt char budgets, retrieval over-fetch multiplier, per-document diversity cap, and the inference context window all reshape when the tier changes. The Settings icon picker shows a checkmark badge on the active variant, and the sidebar / settings header / onboarding brand mark all live-follow the user's pick.
2.2.0 — rebrand to ATHENS. All user-facing labels, the Dock display name, app icon, and brand marks now use the new identity. On-disk storage paths (the vault folder, Application Support subfolder, and bundle identifier are unchanged within a single bundle-ID major version) so existing libraries keep working without migration.
- Imports PDFs, images, text files, Word documents, spreadsheets, presentations, emails, calendar files, audio, video, and other common document formats.
- Stores originals in a local document vault, defaulting to
~/Documents/Athenaeum Library. - Extracts text from PDFs and common text formats, with Apple Vision OCR for images and scanned documents.
- Transcribes imported audio and video files locally when
whisper-cliand a Whisper GGML model are installed. - Classifies documents with a 1,100+-term controlled tag vocabulary and local LLM tagging.
- Tracks titles, filenames, file types, sizes, correspondents, dates, summaries, tags, processing state, and searchable text in SwiftData.
- Builds a local vector index for document chunks and supports document chat through RAG, with optional Tag Chat filters that limit answers to selected document tags.
- Shows a trust screen during onboarding before import, explaining that documents, originals, metadata, vector indexes, and AI processing stay local and that data can be exported or deleted anytime.
- Shows an AI disclaimer in key AI surfaces: ATHENS can make mistakes, source docs should be verified, and outputs are not legal, medical, tax, or financial advice.
- Creates an encrypted
.athensbackupmigration archive from Settings → Storage, bundling vault originals, SwiftData JSON, recovered originals, and local vector stores. - Auto-tiers the model lineup to the host Mac — 8 GB MacBook Airs run a Compact set (Qwen 3B); 16 GB Macs get Standard (Qwen 7B + MiniCPM-V); 24+ GB machines unlock Performance (Qwen 14B + MiniCPM-V). User-overridable in Settings.
- Sidebar tags are user-pinned (cap 10); a dedicated All Tags screen browses the full vocabulary with A–Z grouping, search, and right-click pin/unpin.
- Bulk batch actions for selected documents: tag, auto-tag, clear tags, auto-name, export, delete.
- Exports originals, extracted text, JSON metadata, or CSV catalog rows, and shares originals through the macOS Share Sheet or direct AirDrop from the right-click menu.
Athenaeum/
AthenaeumApp.swift App entry point, commands, SwiftData container
ContentView.swift Main navigation, service setup, vault scanning
Models/ SwiftData document and tag models
Services/ Import, OCR, metadata, search, RAG, LLM, vault, export
Theme/ Japandi visual system and view modifiers
Views/ Sidebar, library, detail, chat, settings, onboarding
Assets.xcassets/ App icon, brand marks, color assets
ATHENS Brand/ Current brand kit (mark, wordmark, app icons, JSX source)
Athenaeum Brand/ Archived previous brand kit (pre-2.2.0)
llama.xcframework/ Bundled llama.cpp framework used by the app target
Athenaeum.xcodeproj/ Xcode project (target name kept for build-system stability)
ATHENS starts in AthenaeumApp, which creates the SwiftData model container for Document and Tag, registers app commands, and opens ContentView. (The Swift type name is unchanged to avoid a target rename; only user-facing labels were rebranded.)
ContentView wires the core services together:
DocumentVaultServiceowns the user-visible vault and security-scoped folder access.DocumentVaultMonitorwatches the vault for Finder-added documents.DocumentProcessororchestrates import, text extraction, metadata refinement, classification, persistence, and RAG indexing.VisionOCRServicehandles native OCR for images and scanned documents.TranscriptionServiceprepares media as temporary WAV audio and calls local Whisper for audio/video transcripts.LocalLLMServiceusesLlamaContextactors to load and run local models. Two roles that point at the same file share a single in-RAM context.VectorStorepersists embeddings for local semantic search. It detects embedding-dimension mismatches on load so the library can be re-embedded when the embedder changes.RAGServicechunks documents, generates retrieval-tuned embeddings with the dedicated embedding model, retrieves relevant context, and streams chat answers with citations.ModelDownloaderdownloads the configured GGUF models into Application Support. Both this andLLMModelDescriptor.defaultsare tier-aware — see Local Models → Hardware tiers below.HardwareProfilerreads available unified memory and resolves aHardwareTier(Compact / Standard / Performance / Workstation). The user can override the auto-detected tier from Settings; everything downstream picks up the change viaNotificationCenter.modelsDidChange.
The UI is organized around a three-pane macOS layout: sidebar navigation, a library or chat content area, and an inspector-style detail/preview pane.
ATHENS looks for GGUF models in:
~/Library/Application Support/Athenaeum/Models
For audio/video transcription, ATHENS also checks for local Whisper files:
~/Library/Application Support/Athenaeum/Whisper/whisper-cli
~/Library/Application Support/Athenaeum/Whisper/Models/ggml-small.en.bin
Homebrew whisper-cli is also detected at /opt/homebrew/bin/whisper-cli or /usr/local/bin/whisper-cli. You can override paths while developing with ATHENS_WHISPER_CLI and ATHENS_WHISPER_MODEL.
This is a documentation app, not a benchmark — ATHENS picks the lightest lineup that does the job well on the host Mac. HardwareProfiler reads ProcessInfo.processInfo.physicalMemory at launch and chooses a tier:
| Tier | RAM | Tagger + Chat | Embedding | Vision | On-disk |
|---|---|---|---|---|---|
| Compact | < 12 GB | Qwen 2.5 3B Instruct Q4_K_M | Nomic Embed v1.5 | — (Apple Vision OCR) | ~2 GB |
| Standard | 12–20 GB | Qwen 2.5 7B Instruct Q4_K_M | Nomic Embed v1.5 | MiniCPM-V 2.6 Q4_K_M | ~10 GB |
| Performance | 20–40 GB | Qwen 2.5 14B Instruct Q4_K_M | Nomic Embed v1.5 | MiniCPM-V 2.6 Q4_K_M | ~14 GB |
| Workstation | ≥ 40 GB | Qwen 2.5 14B Instruct Q4_K_M | Nomic Embed v1.5 | MiniCPM-V 2.6 Q4_K_M | ~14 GB |
The user can override the auto-detected tier in Settings → AI Models ("For This Mac (Recommended)" / Compact / Standard / Performance / Workstation). Model Status surfaces the active tier with a rationale, the detected RAM, and the model tiles for the chosen lineup.
Each tier also carries a HardwareTier.Tunables block (chunk size, chunk overlap, RAG top-K, per-chunk char budget, total prompt char budget, retrieval over-fetch multiplier, per-doc diversity cap, n_ctx, GPU layer count, max inference threads, idle-unload window). The thread budget is additionally clamped to performance-core count minus one (HardwareProfiler.recommendedInferenceThreads), so efficiency cores and one P-core always stay free for the rest of the system. LocalLLMService runs two headroom monitors: an idle timer that unloads all contexts after the tier's idle window (Compact 5 min → Workstation 20 min) and a DispatchSource memory-pressure handler that unloads immediately on warning/critical. Closing the last window also releases model memory while the app stays running; quitting tears everything down and terminates any whisper-cli child process. Switching tiers writes the indexing / retrieval / inference values into UserDefaults, and RAGService reads the prompt-side budgets directly from HardwareProfiler.activeTunables on every call.
Loaded LlamaContext actors hold their n_ctx captured at init time, so the inference context window can't change on a live actor. LocalLLMService.markAllContextsStale() (called by ContentView on .hardwareTierDidChange) sets a flag; the next call to contextForRole(_:) or generateFromImage(...) runs purgeStaleContextsIfNeeded(), which unloads every cached context (deduped so shared tagger+chat contexts unload exactly once) and lets the load path re-init with the fresh config. Active streams keep running on the old actor — Swift actor serial executors guarantee the unload waits for in-flight work. Net UX: indexing and retrieval shape change immediately; the first chat turn after a tier change costs a 5–15 s model warmup, then everything tracks.
| Tier | n_ctx | Chunk / overlap | top-K | per-chunk chars | total prompt chars | over-fetch × | per-doc cap |
|---|---|---|---|---|---|---|---|
| Compact | 4096 | 384 / 48 | 4 | 800 | 4 500 | 5× | 2 |
| Standard | 4096 | 512 / 64 | 6 | 1 200 | 8 000 | 6× | 3 |
| Performance | 8192 | 640 / 96 | 8 | 1 500 | 12 000 | 6× | 3 |
| Workstation | 8192 | 768 / 128 | 10 | 1 800 | 16 000 | 8× | 4 |
On first launch the active tier's tunables are written once (gated by didApplyInitialHardwareTunables in defaults) so a fresh install starts at the right shape without the user opening Settings.
- Tagger + Chat share a single GGUF file.
LocalLLMService.contextForRolenotices the shared filename and reuses one in-RAMLlamaContextinstead of loading the weights twice. - Embedding uses Nomic Embed Text v1.5 (768-dim, contrastively trained).
RAGServiceprepends the model's requiredsearch_document:/search_query:task prefixes. - Vision uses MiniCPM-V 2.6 for enhanced OCR on scanned PDFs and photographed receipts when Apple's native Vision framework alone isn't enough. Skipped entirely on Compact tier.
Loaded model contexts are tied to the app lifecycle. ContentView registers the LocalLLMService when the app opens, and the macOS termination delegate delays quit just long enough for shutdownForAppTermination() to cancel active streams and unload all cached Llama contexts.
Document import still works without models installed; ATHENS falls back to native text extraction, Apple Vision OCR, and a rule-based offline classifier where possible.
When the active embedder's output dimension stops matching what's persisted in the vector store, the store wipes itself on next launch and indexExistingDocumentsIfNeeded re-embeds the library in the background. The same flow handles tier changes that swap the embedder.
Every tagging attempt is mirrored to a permanent log at:
~/Library/Containers/<bundle-id>/Data/Library/Application Support/Athenaeum/tagger.log
(or the equivalent unsandboxed path if you're running outside the sandbox). Lines include the prompt length, the raw model response, the parsed tags, the post-validation tags, and explicit UNPARSEABLE JSON / THREW markers when the LLM stumbles.
- macOS 15.7 or newer, based on the current Xcode deployment target.
- Xcode with the macOS SDK.
- Apple Silicon or Intel Mac supported by the bundled
llama.xcframework. - Several GB of free disk space if downloading the default local models.
Open Athenaeum.xcodeproj in Xcode and run the Athenaeum scheme.
From the command line:
xcodebuild -project Athenaeum.xcodeproj -scheme Athenaeum -configuration Debug buildThe Tools/ directory contains standalone Swift smoke tests for core flows. They are not currently wired into an Xcode test target, but they document and exercise the expected behavior for vault storage, import processing, fallback tagging, OCR, RAG, and export paths.
Use Settings → Storage → Create Backup... to make a portable encrypted backup. The app asks where to save the archive, then asks for a passphrase. Keep that passphrase somewhere safe; it is required to unlock the backup on another Mac and is not stored by ATHENS.
The backup format is a single .athensbackup file. It includes:
manifest.jsonwith app/build, source Mac, counts, and source paths.SwiftData/swiftdata-export.jsonwith documents, tags, folders, word-bank entries, and saved chat records.Originals/Vault/with files from the document vault.Originals/Recovered/with any original file blobs still present in SwiftData when a vault file is missing.VectorStores/with localvector_store*.jsonfiles from Application Support.
ATHENS is intentionally local-first:
- Original files live in the local document vault.
- Metadata is stored locally with SwiftData.
- Vector indexes are stored locally.
- AI inference is designed to run through local GGUF models.
- Migration backups are encrypted locally before they are written to the chosen destination.
The app includes network client entitlement so it can download models from Hugging Face when requested.