TreeMap
무료 오픈소스 디스크 사용량 시각화 도구로, 사각형 트리맵·중복 파일 탐색·디스크 가득 예측·정리 시 파일을 휴지통으로만 이동한다
MacOS local AI notebook
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A local-first, privacy-respecting desktop app inspired by
NotebookLM. Import your sources, chat with them
grounded in citations, and generate documents — running 100% on your
machine when you want it to. No accounts, no cloud requirement, nothing
leaves your laptop by default.
Chat with any model you already have (see
docs/RFC-inference-providers.md):README 전문 보기 ↗A local-first, privacy-respecting desktop app inspired by NotebookLM. Import your sources, chat with them grounded in citations, and generate documents — running 100% on your machine when you want it to. No accounts, no cloud requirement, nothing leaves your laptop by default.
Chat with any model you already have (see docs/RFC-inference-providers.md):
Whatever answers, your sources stay on-device: embeddings default to the built-in private embedder, podcast audio is voiced locally by Kokoro, and image OCR runs through your own Ollama vision model.
Alchemy helps hold the thread without taking it over. Sources can be opened, citations lead back to the evidence, and notebooks remain portable as files. Night Shift writes notes and reports. It will not act outward.
Built with Tauri 2 + React front-end, a Rust backend, LanceDB for embedded vector + relational storage, and a Linear-inspired UI with 37 themes.
One minute of Alchemy — full demo with sound: an agent fills a notebook live over MCP, chat cites exact passages, and the notebook becomes a two-host podcast voiced on-device.
Notebooks — a home screen of notebooks (most-recent first); opens to your last one.
Sources — import PDF, the whole Office family (.doc / .docx /
.ppt / .pptx / .xls / .xlsx / .xlsb), OpenDocument
(.odt / .ods / .odp), RTF, EPUB,
Box Notes (.boxnote), CSV/TSV,
images, text, Markdown, paste text, or fetch a URL — including
link-shared Google Docs, Sheets, and Slides (paste the link, or drag the
.gdoc / .gsheet / .gslides files from a local Google Drive folder). Each is
extracted, chunked, and embedded locally. Drag-and-drop onto the Sources panel.
File sources remember their on-disk path — Refresh re-reads a changed file
(and URL sources re-fetch); Show in Finder jumps to the original.
Failed/blocked imports show an error badge and can be retried; edited/refreshed
sources are re-embedded.
Search your Mac — don't remember where a file lives? Type a few characters
in Add Source and a Spotlight-backed search returns ranked file and folder
hits, addable in one click. Ingestible, name-matching, recently-modified files
float to the top, and Trash / node_modules / ~/Library noise is filtered
out. Adds route through the same path as a drag-and-drop, so folders become
synced folder sources and OKF bundles import exactly as they would otherwise.
Folder sources — add any folder, or start from a detected cloud sync root
(Google Drive, OneDrive, Dropbox, Box, iCloud Drive) with one click and
drill down to a subfolder. It scans supported files, keeps syncing on a timer,
and lists cloud placeholders without downloading them — iCloud stubs hydrate
on their own in the background, and Dropbox Paper (.paper) / Google
.gdoc·.gsheet·.gslides stubs resolve to their online docs.
Mac apps as sources — connect Apple Notes (individual notes), Reminders lists, rolling Calendar windows, and Stocks watchlists via ; they re-sync automatically. Notes can be edited (and reminders added) from inside Alchemy — writes go to the real app and sync back.
┌──────────────────────────────── Tauri window ────────────────────────────────┐
│ React + Tailwind │
│ Home (notebook picker) | Sources │ Chat (streaming) │ Studio (docs+notes) │
└───────────────────────────────── IPC (invoke / events) ──────────────────────┘
│
┌───────────────────────────────── Rust backend ───────────────────────────────┐
│ commands.rs Tauri command surface + per-model stats │
│ ingest.rs extract (anydoc: office/odf/rtf/epub/csv → GFM; pdf/url/text) │
│ → normalize → structure-aware │
│ chunking (paragraphs/headings, title+section context prefix) │
│ pdf.rs PDFium page rasterization for scanned-PDF OCR │
│ ai/ollama.rs embeddings, streaming chat, OCR over Ollama HTTP │
│ agent.rs agentic "deep research" retrieval loop │
│ rag.rs retrieval prompt assembly + generator prompts │
│ router.rs semantic router: routes questions to likely notebooks │
│ trace.rs local retrieval trace JSONL (stages, warnings, citations) │
│ db.rs LanceDB tables: notebooks, sources, chunks(+vectors+FTS), │
│ messages, notes, report_schedules, routes; hybrid search │
│ (RRF + tie-break), diversity caps, search traces │
└──────────────────────────────────────────────────────────────────────────────┘
│
Ollama (localhost:11434)
The RAG loop: a question is embedded and the chunks table is searched two
ways — vector similarity (finds paraphrases) and BM25 full-text (finds exact
names, codes, and numbers that embeddings miss) — with the two result lists
merged by reciprocal rank fusion (deterministic: score ties break by chunk id,
so the same question always cites the same passages). Every retrieval also
appends a local trace line (stages, warnings, citations) to
traces/retrieval.jsonl, and agents can call the MCP search_debug tool to
see exactly why a passage did or didn't surface. Chunks are structure-aware:
whole paragraphs
packed to ~280 words, headings kept with their sections, and each chunk is
embedded with a [Doc title › Section] context prefix (the stored text stays
verbatim so citation highlighting still works). The top passages become
numbered excerpts in the prompt, and the model answers with [n] citations
that map back to the retrieved chunks shown in the UI.
See docs/ARCHITECTURE.md.
In agent mode (agent.rs), the model plans its own retrieval before answering.
Each step it emits one JSON action; evidence accumulates until it decides it
has enough:
User question
│
▼
┌─ Planner loop (≤5 steps, one JSON action per step) ──────────────────────────┐
│ │
│ "search <query>" hybrid search (vector + BM25, RRF) → top-20 pool │
│ │ │
│ ▼ rerank (one model call) │
│ the ≤5 passages that actually answer ─► evidence pool │
│ 180-char snippets ─────────────────────► transcript │
│ │
│ "read <source>" fetch full text (shared budget: │
│ 120k chars gateway / 12k local) │
│ │ │
│ ▼ sub-read (one model call) │
│ distill against the question into │
│ verbatim quotes (≤4k chars) ───────► evidence pool │
│ same distillate ───────────────────► transcript │
│ │
│ "answer" enough evidence — exit loop │
│ │
│ The transcript (searches + distilled reads so far) is re-sent to the │
│ planner each step so it can decide what's still missing. │
└──────────────────────────────────────────────────────────────────────────────┘
│ fallback: nothing gathered → direct top-8 vector search
▼
┌─ Writer (one streamed call) ─────────────────────────────────────────────────┐
│ grounding rules + persona │ last 6 chat turns │ full source manifest │
│ numbered excerpts [1..n] from the evidence pool │
│ └─► streamed answer citing [n], mapped back to sources │
└──────────────────────────────────────────────────────────────────────────────┘
│
▼
Persisted message — citation snippets are the distilled verbatim quotes, so
the excerpts shown in the UI are exactly what the writer saw, and clicking a
citation highlights real passages in the source.
Because a read returns distilled evidence rather than raw text, the writer's context stays small no matter how many or how large the read documents are — the read budget bounds each sub-read call, not the final prompt.
Studio generators and scheduled reports share the retrieval improvements too: they build their corpus by budgeting fairly across all sources (waterfill), and any source that exceeds its allocation gets the same distillation treatment — the overflow is distilled against the generation instructions and appended, so a big source contributes its relevant passages instead of losing everything past the cut.
Meta-chat answers questions across every notebook at once, through a staged
pipeline where each stage earned its place in the eval harness
(cargo test --lib retrieval_eval -- --nocapture, ranked metrics in
docs/RFC-retrieval-maturity.md):
A deterministic scale fence (eval_scale_fence) makes the corpus-scale claim
falsifiable: across synthetic 1M / 3M / 10M-char corpora, exact and paraphrase
recall both hold at 1.00 while adaptive k grows 10 → 13 — recall flat from 1M
to 10M, a passing eval rather than extrapolation.
The UI traces long-running chat work through Tauri events. ChatPanel starts a
send through the Zustand store and api.sendMessage / api.sendMessageAgentic;
the backend persists the user turn, emits chat://step progress labels for
tooling and agent work, emits chat://token deltas as the model streams, then
emits chat://done after the assistant message is saved. The store appends
live text into streamingText, records progress labels in steps[], and then
reloads canonical messages, sources, notes, and report schedules.
Every notebook is a folder of markdown (the Open Knowledge Format), and the folder is the sync. There is no server.
~/Library/Mobile Documents/iCloud~com~thrashr888~alchemy/Documents), or
~/Documents/Alchemy when iCloud Drive is off. Point it at a Dropbox or
Google Drive folder and that folder is the sync instead.index.md, sources/ with one concept
file per source (its extracted text under a single frontmatter block that
names the source, its origin, and its sync identity), notes/,
references/ for copied originals such as PDFs, sync/ for per-Mac
stamps, log.md as a short history, and conflicts/.conflicts/, never over the other copy and kept for
30 days, and nothing is deleted without a deletion record.Details, decisions, and the recovery rules: docs/RFC-okf-live.md.
With Homebrew:
brew tap thrashr888/tap
brew install --cask thrashr888/tap/alchemy
Or download the latest Alchemy_x.y.z_aarch64.dmg from
Releases, open it, and drag
Alchemy to Applications. Builds are signed with a Developer ID and
notarized by Apple, so they open with a normal double-click.
Requires Ollama running locally.
Ollama running locally (ollama serve).
Models pulled — for example:
ollama pull mxbai-embed-large # embeddings
ollama pull gpt-oss:20b # chat (or any chat model)
ollama pull glm-ocr # OCR (optional, for images / scanned PDFs)
Rust (stable) and Node with pnpm. protoc is required to build
LanceDB (brew install protobuf).
The PDFium library (for scanned-PDF OCR) is fetched automatically on first
build by scripts/fetch-pdfium.sh (via build.rs);
no manual step needed.
pnpm install
pnpm tauri dev
The first build compiles LanceDB and is slow; subsequent builds are fast.
cd src-tauri
cargo test # unit tests (+ a graceful-skip Ollama integration test)
cargo fmt -- --check
cargo clippy --all-targets -- -D warnings
CI (.github/workflows/ci.yml) runs the frontend typecheck/build plus the above on every push and PR.
Open Settings (gear icon) to set the Ollama URL and choose models. Defaults:
| Setting | Default |
|---|---|
| Ollama URL | http://localhost:11434 |
| Chat model | gpt-oss:20b |
| Embedding model | mxbai-embed-large |
| Vision model | (unset — OCR disabled) |
Switching the embedding model prompts to re-embed all sources (models produce
incompatible vectors), so retrieval never silently breaks. Data is stored in the OS
app-data directory under lancedb/.
Ollama stays the default, but Alchemy can route chat, generation, deep research,
and OCR through any OpenAI-compatible gateway instead — useful on machines that
can't run local models (e.g. a 16 GB laptop). The same path works for LM Studio,
vLLM, LiteLLM, OpenRouter, enterprise gateways, or Ollama's own /v1 endpoint.
With a gateway selected, sources still stay local: embeddings run on the built-in CPU embedder (a ~30 MB model downloaded on first use, no Ollama required), so nothing but your chat turns leaves the machine.
During onboarding (or later in Settings → Models):
/v1) and paste your API key.Keys are stored only in the local ai_config.json and sent solely as an auth header
to the gateway you configure — never anywhere else. LiteLLM-style gateways with
non-standard key schemes are handled automatically. Alchemy does no in-app
accounting — usage is whatever your gateway bills.
Any OpenAI-compatible endpoint works. Settings that are known-good:
| Provider | Gateway URL | API key | Notes |
|---|---|---|---|
| OpenAI | https://api.openai.com/v1 | sk-… from platform.openai.com | gpt-4o & friends are vision-capable (works for OCR too) |
| Anthropic | https://api.anthropic.com/v1 | sk-ant-… from the console | Via Anthropic's OpenAI SDK-compat layer; sk-ant- keys get the right headers automatically |
| OpenRouter | https://openrouter.ai/api/v1 | sk-or-… from openrouter.ai/keys | One key, hundreds of models (anthropic/…, google/…, …) |
| Groq | https://api.groq.com/openai/v1 | from console.groq.com | Very fast open-weight models |
| IBM Bob | https://api.us-east.bob.ibm.com/inference/v1 | bob_… from the Bob portal (IBM-internal) | Bob's Apikey scheme & team headers are handled automatically |
| LM Studio | http://localhost:1234/v1 | (none) | Local server; load a model in LM Studio first |
| Ollama | http://localhost:11434/v1 | (none) | Ollama's own OpenAI-compat endpoint (or just use the native Ollama provider) |
You can leave the Gateway URL empty for OpenAI, Anthropic, OpenRouter, Groq, and Bob-style keys — Alchemy infers the URL from the key format.
For OCR of images and scanned PDFs, set a vision-capable model as the gateway
vision model (e.g. gpt-4o, a Claude model, or any vision model on OpenRouter);
leaving it empty disables OCR. Embeddings never leave your machine regardless of
provider — the built-in on-device embedder (potion-base-8M) indexes your sources.
Releases are cut locally on Apple Silicon — one command builds, signs, notarizes, and publishes:
scripts/release.sh 0.4.2
See RELEASE.md for what it does, one-time setup (Developer ID
cert + notary profile), and the manual CI fallback
(.github/workflows/release.yml, triggered from
the Actions tab). Builds are signed with a Developer ID and notarized, so the
.dmg opens with a normal double-click.
The app bundles the PDFium library
(for scanned-PDF OCR). An Intel (x86_64) build is possible on a macos-13 runner
but those runners queue for hours; it can be re-added to the matrix if needed.
Video overviews are intentionally out of scope. Notes are not embedded into retrieval on their own — Convert to source to make a note retrievable.
Command menu — press ⌘K anywhere to search notebooks, add sources, generate documents, toggle panels, and switch themes.
Slash commands — type / in the chat composer to open a picker over every
command, grouped Generate / Learning / Documents / Actions: all 19 generators
(trailing text becomes custom instructions) plus /add, /model,
/research, /grep, /note, /report, and /clear. Fuzzy matching
tolerates spaces and hyphens ("study guide" → study_guide), Tab
completes, and an unrecognized slash just sends as ordinary text. /grep runs
an exact-match ripgrep search across your sources inline — no model call,
nothing persisted to the transcript. The whole list is also browsable in
Settings → Shortcuts.
@ mentions — type @ in the composer to name a source, folder, or note;
the question retrieves from exactly what you named (a folder means its
files), overriding the source checkboxes for that one message.
Ask everything — the ⌘K palette (and the homepage ask box) answers questions across all notebooks at once: semantic routing to the likely notebooks, hybrid retrieval with diversity caps, optional deep rerank on gateway models, a streamed answer with notebook chips, and citations that jump straight to the passage ("which notebook has the SNDK stock data?"). Broad questions — "summarize the themes," "what do these disagree on?" — are answered across every relevant source, not just the closest passages. ⌥Space summons it from anywhere.
Part of the Mac — alchemy:// deep links, a menu bar extra (ask, add the
clipboard as a source, recent notebooks), "Add to Alchemy" in every app's
Services menu, and Spotlight-indexed notebooks and notes.
Web clipper — the Alchemy Web Clipper
Chrome extension adds the current page, a link, or a text selection to a
notebook from the toolbar or right-click menu. Clipping a whole page hands
Alchemy the rendered DOM from your logged-in tab — so private and
login-walled pages the app could never fetch itself still capture — over a
local 127.0.0.1 endpoint (Settings → Sources → Web clipper); nothing
leaves your Mac. Firefox and Safari builds come out of the same source and
clip URLs, links, and selections (see extension/).
OCR — image sources and scanned/image-only PDFs are transcribed by a local
vision model (dedicated OCR models like glm-ocr / deepseek-ocr recommended).
Grounded chat — streamed answers that cite the exact source passages they drew from, with a "Deep research" agentic mode that plans multiple retrieval steps. Copy a response or save it as a note.
Retrieval at scale — search quality holds as a notebook grows past millions of characters. The retrieval budget adapts to corpus size, and a scale fence keeps recall flat from 1M to 10M chars (verified) — a large source list stays fully searchable instead of diluting every answer.
Sources at scale — the Sources panel stays fast past 5,000 sources: windowed rendering, a filter box with kind, tag, and freshness facets (including "uncited" — sources retrieval has never used), and busy web domains folding into collapsible groups.
Grow — a center pane (Chat ⇄ Reader ⇄ Gallery ⇄ Grow) that proposes ways a notebook could grow. Questions it answered thinly become standing questions; Alchemy then suggests files already on your Mac (Spotlight), pages your sources keep citing, and — per-notebook opt-in, metered inside Firecrawl's free tier — results from the web. Every addition is an explicit Add; dismissals decay after 30 days.
Tidy & organize — old sources retrieval has never cited are proposed
for muting or removal (never automatic), and near-duplicate tags
(vessel / vessels) get one-click merges.
Wiki index & entity pages — one click writes a "Notebook index" note mapping every source by tag with clickable title links, plus a page per registry entity filed in the notebook. The wiki re-derives itself with background work, and it's all ordinary notes — portable through OKF, editable by agents.
Source gists — every source gets a short distilled overview in the background, so corpus-wide questions ("what's in here?", "which source covers X?") find the right document even when no single passage is an obvious match. Captured web pages also get a per-chunk context pass and shed navigation cruft, so search over clipped articles reads much closer to search over clean documents.
Live view nav — web sources opened as the actual page get back/forward buttons, the current address, and an "Add as source" offer when you wander onto a page the notebook doesn't have yet.
Reader — sources and notes open in a center-column reader (Chat ⇄ Reader
tabs in the toolbar), never a modal: click through the rails to swap
documents, with browser-style back/forward (⌘[ / ⌘]), j/k to step
through the notebook, ⌘F find-in-source, and per-document word/char/token
counts. Markdown sources render as real markdown (GitHub-flavored, including
<details> and friends), relative links resolve — a link to another
source in the notebook jumps straight to it, wiki-style — and your chat
reading preferences (font, size, alignment) apply to documents too. Code
files render with syntax highlighting, with find-in-source over the
colored view.
Select-to-ask — highlight any passage in the source reader to Explain it, Compare it against your other sources, or stage it in the chat composer with your own question.
Audio Overview — one click turns a notebook into a two-host podcast episode, scripted by your chat model and voiced entirely on-device by Kokoro-82M neural TTS (a one-time ~93 MB download). The script stays readable and editable as a note; the episode plays inline.
Studio generators — one-click Summary, FAQ, Study guide, Briefing, Timeline, Insights (cross-source connections, contradictions & surprises), Data table, Round table (product, engineering, and design critique the sources from their own risk lenses, then close on agreements and open questions), Problems (finds errors/gaps/contradictions), Flashcards, Quiz, Slide deck, a Mind map, and a UML diagram, plus HashiCorp-style PRD, PR/FAQ, RFC, and a Skill (SKILL.md) generator. Add custom instructions, and rebuild any document against the latest sources.
Artifacts are real, not text dumps — flashcards are a flippable deck with Leitner spaced repetition (grade yourself; cards return on a 1/3/7/21-day schedule, persisted per deck); quizzes grade each answer with the key's explanation and a running score; slide decks are Marp-style markdown rendered as true 16:9 slides — layouts inferred per slide, color themes drawn from the app's own theme catalog plus a font axis (both switchable, persisted in front-matter), a fullscreen Present mode, and one-click PDF export (landscape 16:9 pages; flashcards export a study sheet) — all local via the native print system; mind maps are a native SVG on a pannable canvas (drag or scroll, Photoshop-style), and UML diagrams render class, sequence, state, ER, and component views on that same canvas, with the model's source one click away.
Notes — a WYSIWYG editor (Markdown under the hood), copy to clipboard, Convert to source to fold a note into the retrievable source set, and Open in window for a full-size reader (mind maps especially).
Notebooks live as files (OKF) — every notebook keeps itself on disk as an
Open Knowledge Format
folder: markdown concepts with YAML frontmatter, indexes, a log, and the
original PDFs and images under references/. New notebooks go to
iCloud Drive/Alchemy when iCloud Drive is on (~/Documents/Alchemy
otherwise; pick any folder, Dropbox included). The same folder opens on your
other Mac, a folder someone shares with you opens as a linked notebook, and
edits made in the folder by you or an agent flow back into the app. Export a
single .okf.zip to send a notebook by mail, add a bundle folder as a living
source, or import one as a copy.
Agent access (MCP) — an embedded MCP server (localhost-only) lets agents
create notebooks, add sources, run hybrid search (per-notebook or across the
whole corpus), write notes, and act on connected Mac items (update an Apple
Note, add a reminder) — and connect Mac items themselves by passing a
cider:// origin (a Reminders list, Notes note, Calendar window, or Stocks
watchlist) to add_source — with changes appearing live in the app. One-click connect (config + companion skill) for
Claude Code, Claude Desktop, OpenAI Codex, GitHub Copilot, VS Code, Cursor,
OpenCode, Gemini CLI, Google Antigravity, Factory Droid, AWS Kiro, IBM Bob,
Hermes, Prime Agent, and Pi in Settings → Agents (see docs/RFC-mcp-server.md). The companion skill is
also on skills.sh:
npx skills add thrashr888/alchemy@alchemy
Claude Code can take the skill and the server together as a plugin:
claude plugin marketplace add thrashr888/alchemy
claude plugin install alchemy@alchemy
Command line — a thin alchemy client talks to the embedded MCP
server in the running app; it does not open a second database or start a
headless Alchemy process. Install it with Homebrew:
brew install thrashr888/tap/alchemy-cli
Then add files, URLs, or piped text and search from any directory:
alchemy notebooks
alchemy add report.pdf https://example.com --notebook "Project Atlas"
pbpaste | alchemy add --notebook "Project Atlas" --title "Meeting notes"
alchemy search "renewal risk" --notebook "Project Atlas"
alchemy search "where did I save the contractor agreement?" --json
An omitted --notebook searches across all notebooks. --json keeps every
command scriptable. The app must be running with MCP enabled; discovery uses
its owner-only app-data mcp.json for the URL and local bearer token, with
matching --mcp-url / --mcp-token environment overrides when needed.
Periodic reports — schedule a notebook to refresh its URL sources and generate a timestamped report note on an interval; each run sees the previous report and calls out what changed since.
Model tooling — live chat/embed health check, per-model tokens/sec tracking, MLX-accelerated model suggestions, and safe re-embed-on-model-switch.
37 themes — Acid Garage, Blueprint, Camo Ice, Camo Jungle, Camo Sand, Camo Urban, Carrera, Carrera Dark, Catppuccin Latte, Claude, Dracula, Durandal, GitHub, GitHub Light, Gruvbox, IBM Carbon, IBM Carbon Light, Italia, Light, Matrix, Midnight, Monokai, Night City, Nord, One Dark, OpenAI, Paddock, Panigale, QDOS, Rosé Pine Dawn, Sakura, Sepia, Slate, Solarized, Solarized Light, Synthwave '84, Tokyo Night.
Themed design elements — themes with strong iconography restyle the dithered backdrop to match (Matrix code rain, Synthwave '84 a striped sun over a perspective grid, Sepia static paper grain, Carrera a sweeping tachometer, Italia a slipstream at speed, Panigale a trellis lattice), open the hero on their own transmutation sigil, and bring their own thinking verbs; a daily epigraph is generated by your local model (curated fallbacks when inference is off). Each notebook's color carries through the workspace — title dot, capacity gauge, and the chat sigil.
Follows your system text size — the entire interface scales to the macOS Accessibility text-size setting (System Settings → Accessibility → Display), re-reading it on window focus, since a webview otherwise ignores it outright. Your own chat and reader size preferences compose on top of it, and PDF export is pinned so printed pages never scale.